质数分布 为不大于x的质数的个数,有
质数近似估计 第x个质数的近似估计:
时间复杂度为
cpp123456789void pre(int n){
for(int i=2;i<=n;i++){
if(!vis[i]) prime[++cnt]=i;
for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
vis[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
}
如果被分解的数不太大,可以使用线性筛筛出小于等于它的所有质数。枚举每个质数,再一个一个试除
事实上,即使被分解的数到了 的范围,也是可以用上述方法的
考虑到原数只可能有一个大于 的质因子,所以我们只需要筛出 以内的质数,然后再一个个试除
除到最后如果不为1的话,那么剩下那个数就是原数最后的质因子
在线性筛时,vis数组不单纯记录有没有被筛掉,而是记录被哪个数字筛掉了。最后根据vis数组就可以做到分解质因数
cpp12345678910int prime[_],cnt,vis[_];
inline void init(int n){
for(int i=2;i<=n;i++){
if(!vis[i]) prime[++cnt]=i,vis[i]=i;
for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
vis[prime[j]*i]=prime[j];
if(i%prime[j]==0) break;
}
}
}
cpp123456789while(t--){
int x;cin>>x;
int ans=0;
while(x!=1){
ans^=vis[x];
x/=vis[x];
}
cout<<ans<<endl;
}
将正整数N分解为
则有:
N的正约数的个数为
N的所有正约数之和为
欧几里得算法
更相减损术
高精度求gcd
若a和b均为偶数,;
若a为偶数b为奇数,;
若a和b均为奇数,
费马小定理
若 互质且 为质数,则有
进一步推得
扩展欧拉定理
对于任意 都有
cpp123456int exgcd(int a,int b,int &x,int &y){
if(!b){return x=1,y=0,a;
int r=exgcd(b,a%b,y,x);
y-=a/b*x;
return r;
}
即可求出方程 一组特解
求出解的增量:
与原方程的倍数:
得原方程的特解:
然后可以利用增量来调整解
比如,若 则可以 来调整到x的最小非负整数解
cpp123456789101112int excrt(){
int M=m[1],A=a[1],x,y,d;
for(int i=1;i<=n;i++){
d=exgcd(M,m[i],x,y);
if((A-a[i])%d!=0) return -1;
x=((A-a[i])/d*x%(m[i]/d)+m[i]/d)%(m[i]/d);//可能这一步需要龟速乘
A-=x*M;
M=M/d*m[i];
A=(A%M+M)%M;
}
return A;
}
cpp123int b,p,x,y;
exgcd(b,p,x,y);
x=(x%p+p)%p;
x即为b在模p下的逆元
时间复杂度
要求p必须为质数
cpp1int x=qpow(b,p-2,p);
x即为b在模p下的逆元
时间复杂度
cpp12345int n,p;
inv[0]=0,inv[1]=1;
for(int i=2;i<=n;i++){
inv[i]=p-(p/i)*inv[p%i]%p;
}
时间复杂度
常用于组合数取模
cpp1234567891011const int mod;
int fac[1000006];
int inv[1000006];
void pre(){
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
inv[n]=pow(fac[n],mod-2);
for(int i=n-1;i>=0;i--){
inv[i]=inv[i+1]*(i+1)%mod;
}
}
时间复杂度
借助线性推乘法逆元的思想
对于数列
定义 f[i]=f[i-1]*a_i%mod;
先求最后一项的逆元 g[n]=qpow(f[n],mod-2);
然后线性推 g[i]=g[i+1]*a[i+1]%mod;
则对于 的逆元,为 g[i]*f[i-1]%mod
生成单位矩阵的时候只需要一层循环
Matrix结构体的arr数组记得要memset
看好数据范围,可能需要龟速乘
除了2以外,其他数的欧拉函数值都为偶数
如果 那么 。因此,与x互质的数是成对出现的,并且和为x。由此可知,小于n与n互质的所数的和为
cpp123456789inline int euler(int x){
int phi=x;
for(int i=2;i*i<=x;i++){
if(x%i==0) phi=phi/i*(i-1);///
while(x%i==0) x/=i;
}
if(x>1) phi=phi/x*(x-1);
return phi;
}
cpp12345678910111213141516int phi[_],vis[_],prime[_],cnt;
void pre(){
phi[1]=1;///
for(int i=2;i<=_-6;i++){
if(!vis[i]) prime[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&i*prime[j]<=_-6;j++){
vis[i*prime[j]]=true;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];///
break;
}else{
phi[i*prime[j]]=phi[i]*phi[prime[j]];///
}
}
}
}
用于求
我们发现一些 的值是相同的,将相同的作为一个块
设 为当前块的特征值(也就是当前块所有的数都等于这个)
如果 ,那么当前块的右边界为n
如果 ,那么当前块的右边界为