初阶

扩展欧拉

\(k\ge\varphi(m)\)时,\(b^k\equiv b^{k\%\varphi(m)+\varphi(m)}(\bmod m\))

扩展CRT

推式子合并同余方程。

https://www.cnblogs.com/flashhu/p/9346078.html

扩展BSGS

根号大暴力,就是细节很多。

https://www.cnblogs.com/flashhu/p/9737769.html

扩展Lucas

对于模数不是质数的,唯一分解为\(\prod p_i^{k_i}\),算出组合数对每一个\(p_i^{k_i}\)取模的结果,用CRT合并。

问题在于求\(n!\%p^k\)。

将\(n!\)中所有\(p\)因子提出来,因子个数\(\sum\limits_{i=1}\lfloor\frac{n}{p^i}\rfloor\)。

剩下的数的贡献单独考虑,记为\(F_n\),发现它在模意义下以\(p^k\)为周期,\(fac_n=F_{p^k}^{\lfloor\frac{n}{p^k}\rfloor}F_{n\%p^k}fac_{\lfloor\frac n p\rfloor}\),递归处理。

时间复杂度\(\sum p_i^{k_i}\)。

洛谷P4720 【模板】扩展卢卡斯

#include<bits/stdc++.h>
#define LL long long
#define R register LL
using namespace std;
LL n,m,YL,F[1000009];
void exgcd(R a,R b,R&x,R&y){
if(!b){x=1;y=0;return;}
exgcd(b,a%b,y,x);y-=a/b*x;
}
inline LL qpow(R b,R k,R p){
R a=1;
for(;k;k>>=1,b=b*b%p)
if(k&1ll)a=a*b%p;
return a;
}
LL fac(R n,R p,R k){
return n?qpow(F[k],n/k,k)*F[n%k]%k*fac(n/p,p,k)%k:1;
}
inline LL inv(R n,R p){
R x,y;exgcd(n,p,x,y);
return x<=0?x+p:x;
}
inline LL cnt(R n,R p){
R k=0;
for(n/=p;n;n/=p)k+=n;
return k;
}
inline LL C(R n,R m,R p,R k){
for(R i=F[0]=1;i<=k;++i)
F[i]=i%p?F[i-1]*i%YL:F[i-1];
return fac(n,p,k)*inv(fac(m,p,k),k)%k*inv(fac(n-m,p,k),k)%k*qpow(p,cnt(n,p)-cnt(m,p)-cnt(n-m,p),k)%k;
}
inline LL CRT(R a,R p){
return YL/p*inv(YL/p,p)%YL*a%YL;
}
int main(){
cin>>n>>m>>YL;
R now=YL,lim=sqrt(YL),ans=0;
for(R p=2;p<=lim;++p){
if(now%p)continue;
R k=1;while(now%p==0)now/=p,k*=p;
ans=(ans+CRT(C(n,m,p,k),k))%YL;
lim=sqrt(now);
}
if(now>1)ans=(ans+CRT(C(n,m,now,now),now))%YL;
cout<<ans<<endl;
return 0;
}

进阶

Miller-Rabin&Pollard-Rho

背板子

洛谷P4718 【模板】Pollard-Rho算法

辣鸡卡常题,参考了一下讨论版里的卡常技巧

upd:模数为long long级别的乘法取模原理

如果NOI能用什么__int128的话倒还好说

但是别忘了long double__int128的位长是一样的啊!因此用它做long long级别的运算的精度损失是完全可以接受的。

我们知道\(a*b\bmod p=a*b-\lfloor\frac{a*b}p\rfloor*p\)

然后我们用long double先除后乘,考虑浮点数除法会丢掉小数点后面一个很小的值,而之后强制转换整形是要强制舍去的,所以要加一个eps。

#include<bits/stdc++.h>
#define SL __int128
#define LL long long
#define RG register
#define R RG int
using namespace std;
LL t,n,ans;
inline LL Mul(LL a,LL b,LL p){//㧟的玄学乘法取模
LL d=((long double)a/p*b+1e-8);
LL r=a*b-d*p;
return r<0?r+p:r;
}
inline LL Gcd(LL a,LL b){//㧟的builtin辗转相减
if(!a||!b)return a|b;
int t=__builtin_ctzll(a|b);
a>>=__builtin_ctzll(a);
do{
b>>=__builtin_ctzll(b);
if(a>b)swap(a,b);
b-=a;
}while(b);
return a<<t;
}
inline LL Qpow(LL b,LL k,LL p,LL a=1){
for(;k;k>>=1,b=(SL)b*b%p)
if(k&1ll)a=(SL)a*b%p;
return a;
}
inline LL MR(LL n){
if(n==2)return 1;
if(n==1||(1&n)==0)return 0;
static int a[]={2,3,7,13,61,24251};
LL u=n-1,x,y;R k=0;
while((1&u)==0)u>>=1,++k;
for(R i=0;i<6&&a[i]<n;++i){
x=Qpow(a[i],u,n);
for(R j=0;j<k;++j,x=y){
y=(SL)x*x%n;
if(y==1&&x!=1&&x!=n-1)return 0;
}
if(x!=1)return 0;
}
return 1;
}
inline LL F(LL a,LL c,LL n){
LL t=Mul(a,a,n)+c;
return t<n?t:t-n;
}
inline LL PR(LL n){
if((1&n)==0)return 2;
LL c=rand(),a=rand(),b=a,g;
do{
a=F(a,c,n);b=F(F(b,c,n),c,n);
g=Gcd(n,abs(a-b));
if(g!=1&&g!=n)return g;
}while(a!=b);
return g;
}
void find(LL n){
if(n==1||n<=ans)return;
if(MR(n)){ans=max(ans,n);return;}
LL d=n;
while(d==n)d=PR(n);
while(n%d==0)n/=d;
find(n);find(d);
}
int main(){
srand(time(NULL));
cin>>t;
while(t--){
cin>>n;ans=1;find(n);
if(ans==n)puts("Prime");
else cout<<ans<<'\n';
}
return 0;
}

狄利克雷卷积&杜教筛

积性函数的性质:两个积性函数的狄利克雷卷积还是积性函数。

有一些推式子题里需要通过构造积性函数来加快函数求值。

常用的卷积式

\(\mu*\textbf1=\epsilon\Leftrightarrow\sum\limits_{d|n}\mu(d)=[n==1]\)

\(\varphi*\textbf1=\textbf{id}\Leftrightarrow\sum\limits_{d|n}\varphi(d)=n\)

\(\mu*\textbf{id}=\varphi\Leftrightarrow\sum\limits_{d|n}\frac{n}{d}\mu(d)=\varphi(n)\)

\(\textbf1*\textbf1=\textbf{d};\textbf{d}*\textbf1=\sigma\)(感觉还有很多都是可以相互推出来的)

杜教筛:求积性函数\(f\)的前缀和(记为\(S\))。

构造积性函数\(g\),前提是\(g\)和\(F=f*g\)的前缀和都可以\(O(1)\)算。

\(\sum\limits_{i=1}^nF(i)=\sum\limits_{i=1}^n\sum\limits_{xy=i}f(x)g(y)=\sum\limits_{y=1}^ng(y)\sum\limits_{x=1}^{\lfloor\frac{n}{y}\rfloor}f(x)=g(1)S(x)+\sum\limits_{y=2}^ng(y)S(\lfloor\frac n y\rfloor)\)

\(g(1)S(x)=\sum\limits_{i=1}^nF(i)-\sum\limits_{y=2}^ng(y)S(\lfloor\frac n y\rfloor)\)

看到了可以整除分块+递归的地方。

预处理\(F,g\)到\(n^\frac 2 3\)的前缀和,时间复杂度\(O(n^\frac 2 3)\)。

洛谷P4213 【模板】杜教筛(Sum)

#include<bits/stdc++.h>
#define LL long long
#define UI unsigned int
#define RG register
#define R RG int
using namespace std;
const LL N=2147483648,M=1.7e6,L=2000;
int pr[M],cnt;bool vis[M];
struct Dat{LL p;int u;}s[M],t[L];
Dat&S(UI n){
if(n<M)return s[n];
UI x=N/n;if(vis[x])return t[x];vis[x]=1;
Dat&ans=t[x];
ans.p=(LL)n*(n+1)>>1;ans.u=1;
for(UI l=2,r;l<=n;l=r+1){
r=n/(n/l);Dat&ret=S(n/l);
ans.p-=(r-l+1)*ret.p;
ans.u-=(r-l+1)*ret.u;
}
return ans;
}
int main(){
s[1]=(Dat){1,1};vis[1]=1;
for(R i=2;i<M;++i){
if(!vis[i])s[pr[++cnt]=i]=(Dat){i-1,-1};
for(R j=1,x;j<=cnt&&(x=i*pr[j])<M;++j){
vis[x]=1;
if(i%pr[j]==0){s[x].p=s[i].p*pr[j];break;}
s[x].p=s[i].p*(pr[j]-1);s[x].u=-s[i].u;
}
s[i].p+=s[i-1].p;s[i].u+=s[i-1].u;
}
memset(vis,0,M);
R t,n;cin>>t;
while(t--){
cin>>n;
Dat ret=S(n);
cout<<ret.p<<' '<<ret.u<<endl;
memset(vis,0,L);
}
return 0;
}

Min_25筛

同样是求积性函数前缀和,不过扩展性很强。

yyb巨佬告诉我这是今年新鲜出炉的筛法,吊打了某洲阁筛(话说写这句话的时候是今年的最后一天了)

核心思想是体现在Step2中的将最小质因子相同的数的贡献一起算。

应用前提:对于\(p\in P\),\(f(p)\)是一个简单多项式,\(f(p^e)\)可以快速计算。比某杜教筛不知道高到哪里去了。

时间复杂度玄学,但是跑得快

https://www.cnblogs.com/cjyyb/p/10169190.html

https://www.cnblogs.com/cjoieryl/p/9403579.html

https://www.cnblogs.com/zhoushuyu/p/9187319.html

https://www.cnblogs.com/cx233666/p/10173977.html

https://www.cnblogs.com/GuessYCB/p/10061411.html (都是高级操作)

Step1

把多项式拆开,对每个\(f(x)=x^k\)的项分开算贡献。

把\(\sqrt N\)范围的质数筛出来,记为\(P\)。预处理质数的函数前缀和\(fs\)。

先对于每个\(i\le \sqrt N\)求\(\sum\limits_{x=1}^{\lfloor\frac N i\rfloor}[x\in P]f(x)\)。

设\(g(n,j)\)为\(x\in[1,n]\)中满足\(x\in P\)或\(x\)的最小质因子小于\(P_j\)的\(f(x)\)之和

于是显然有\(g(n,|P|)=\sum\limits_{x=1}^{n}[x\in P]f(x)\)。

实现过程:滚动数组,外层枚举\(j\),直接用一维数组保存每一个\(n=\lfloor\frac N i\rfloor\)当前的\(g(n,j)\)。

内层枚举\(i\),有\(g(n,j)=g(n,j-1)-f(P_j)\cdot(g(\lfloor\frac{n}{P_j}\rfloor,j-1)-fs(j-1))\),结合定义用容斥思想理解。

Step2

开始算答案了。

设\(S(n,j)\)为\(x\in[1,n]\)中满足\(x\)的最小质因子大于等于\(P_j\)的\(f(x)\)之和(注意和\(g\)的区别)

于是我们要求的答案即是\(S(N,1)+f(1)\)(\(S\)里面不包含\(f(1)\))

求\(S(n,j)\)时,分质数和合数算贡献

质数:\(g(n,|P|)-fs(j-1)\)

合数:枚举最小质因子\(P_j\)以及它的次数\(e\),相同的一起算(注意不包含\(f(1)\),因此还有一个尾项)

\(\sum\limits_{k=j}^{P_k^2\le n}\sum\limits_{e=1}^{P_k^{e+1}\le n}S(\lfloor\frac{n}{P_k^e}\rfloor,k+1)f(P_k^e)+f(P_k^{e+1})\)

LOJ6053 简单的函数

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define R RG LL
using namespace std;
const LL N=2e5+9,YL=1e9+7;
LL n,Sq,p,m,pr[N],id1[N],id2[N],w[N],fx[N],gx[N],g1[N];
bool np[N];
inline LL Getid(R x){
return x<=Sq?id1[x]:id2[n/x];
}
void Sieve(){
for(R i=2;i<=Sq;++i){
if(np[i])continue;
pr[++p]=i;fx[p]=(fx[p-1]+i)%YL;
for(R j=i*i;j<=Sq;j+=i)np[j]=1;
}
}
LL S(R n,R j){
if(n<=1||pr[j]>n)return 0;
R x=Getid(n);
R ret=(gx[x]-fx[j-1]-g1[x]+j-1+2*YL)%YL;
for(R k=j;k<=p&&pr[k]*pr[k]<=n;++k){
R p1=pr[k],p2=p1*p1;
for(R e=1;p2<=n;++e,p1=p2,p2*=pr[k])
ret=(ret+S(n/p1,k+1)*(pr[k]^e)+(pr[k]^(e+1)))%YL;
}
return ret;
}
int main(){
cin>>n;
if(n==1)return puts("1"),0;
Sq=sqrt(n);Sieve();
for(R i=1,j;i<=n;i=j+1){
R x=w[++m]=n/i;j=n/x;
(x<=Sq?id1[x]:id2[n/x])=m;
gx[m]=(x+2)%YL*((x-1)%YL)%YL*((YL+1)>>1)%YL;
g1[m]=(x-1)%YL;
}
for(R j=1;j<=p;++j)
for(R i=1;i<=m&&pr[j]*pr[j]<=w[i];++i){
R x=Getid(w[i]/pr[j]);
gx[i]=((gx[i]-pr[j]*(gx[x]-fx[j-1]))%YL+YL)%YL;
g1[i]=(g1[i]-g1[x]+j-1+YL)%YL;
}
return cout<<S(n,1)+3<<endl,0;
}

数论细节梳理&模板的更多相关文章

  1. 图论杂项细节梳理&模板(虚树,圆方树,仙人掌,欧拉路径,还有。。。)

    orzYCB 虚树 %自为风月马前卒巨佬% 用于优化一类树形DP问题. 当状态转移只和树中的某些关键点有关的时候,我们把这些点和它们两两之间的LCA弄出来,以点的祖孙关系连成一棵新的树,这就是虚树. ...

  2. 计算几何细节梳理&模板

    点击%XZY巨佬 向量的板子 #include<bits/stdc++.h> #define I inline using namespace std; typedef double DB ...

  3. 多项式细节梳理&模板(多项式)

    基础 很久以前的多项式总结 现在的码风又变了... FFT和NTT的板子 typedef complex<double> C; const double PI=acos(-1); void ...

  4. 各种反演细节梳理&模板

    炫酷反演魔术课件byVFK stO FDF Orz(证明全有%%%) 莫比乌斯反演 \(F(n)=\sum\limits_{d|n}f(d)\Rightarrow f(n)=\sum\limits_{ ...

  5. C++面向对象类的书写相关细节梳理

    类的问题 继承类的原因:为了添加或者替换功能. 1. 继承时重写类的方法 v 替换功能 ① 将所有方法都设置为virtual(虚函数),以防万一. Virtual:经验表明最好将所有方法都设置为vir ...

  6. 快速数论变换NTT模板

    51nod 1348 乘积之和 #include <cmath> #include <iostream> #include <cstdio> #include &l ...

  7. 【模板整合计划】NB数论

    [模板整合计划]NB数论 一:[质数] 1.[暴力判] 素数.コンテスト.素数 \(\text{[AT807]}\) #include<cstdio> #include<cmath& ...

  8. 深入浅出ES6(四):模板字符串

    作者 Jason Orendorff  github主页  https://github.com/jorendorff 反撇号(`)基础知识 ES6引入了一种新型的字符串字面量语法,我们称之为模板字符 ...

  9. Java 程序动态替换 docx 模板中定制值的实现例子

    项目系统中打印功能,导出 word 文档功能是挺常用的,本文介绍自定文档模板,程序实现模板内容中值替代的功能. 模板文件 template.docx ​ 执行 main public static v ...

随机推荐

  1. 20分钟 看图手写的table

    <html><body><table width="100%" border="1" cellspacing="0&qu ...

  2. dynamo与cassandra区别

    虽说cassandra是dynamo的开源版本,但两者还是有很大区别的. coordinator的选取: 在dynamo论文中,一般是preference list中N个副本的第一个 为什么叫“一般” ...

  3. Centos 7 关闭selinux and firewall

    关闭selinx,重启生效 修改文件 /etc/selinux/config 修改 SELINUX=disabled getenforce #查selinux状态 setenforce #关闭seli ...

  4. # 【Python3练习题 004】输入某年某月某日,判断这一天是这一年的第几天?

    # [Python练习题 004]输入某年某月某日,判断这一天是这一年的第几天? # 思路:先判断是否为闰年,这关系到 2 月份的天数.# 之后再根据月份值把前几个月的天数累积加起来,最后再加上个“日 ...

  5. redis设置防火墙的问题

    Linux 下载安装配置Redis完整步骤   安装: 1.获取redis资源 wget http://download.redis.io/releases/redis-4.0.8.tar.gz 2. ...

  6. HTML5开发之meta标签的viewport使用说明

    随着高端手机(Andriod,Iphone,Ipod,WinPhone等)的盛行,移动互联应用开发也越来越受到人们的重视,用html5开发移动应用是最好的选择.然而每一款手机有不同的分辨率,不同屏幕大 ...

  7. prometheus和metrucs-server (k8s监控)

    资源指标:metrucs-server 自定义指标:prometheus, k8s-prometheus-adapter(转换prometheus数据的格式) 新一代架构: 核心指标流水线:由kube ...

  8. DAY02、正式介绍python

    一.编程语言介绍(***) 1.1.机器语言:直接用计算机能理解的二进制指令编写程序,直接控制硬件 1.2.汇编语言:用英文标签取代二进制指令编写程序,本质也是直接控制硬件 1.3.高级语言:用人类能 ...

  9. WEB测试重点--(转载)

    1.功能测试: 所实现的功能是否和需求一致: js错误 页面链接错误-空链接.死链接.错误链接 按钮无效 未实现功能 报错提示信息不准确或不友好 数据库访问错误 sql注入 文档上传下载问题 -未实现 ...

  10. Python——列表操作

    一.列表中所有元素出现的次数,并输出为字典模式 def count_list(list): b_list = {} for i in set(list): b_list[i] = list.count ...