数论整理(代码篇)
理论方面的内容参见数论整理(理论篇)
1. 快速幂\(O(\log b)\)
其实这个不应该算数论?
//递归实现
long long qpow(long long a,long long b,long long mod)
{
if(b==0)return 1;
long long ans=qpow(a,b/2,mod);
ans=(ans*ans)%mod;
if(b&1)ans=(a%mod*ans)%mod;
return ans;
}
//迭代实现
long long qpow(long long a,long long b,long long mod)
{
long long ans=1,now=a;
while(b>0)
{
if(b&1)ans*=now,ans%=mod;
now*=now,now%=mod;
b>>=1;
}
return ans;
}
2. 最大公因数&最小公倍数\(O(\log \max(a,b))\)
int gcd(int a,int b)
{
if(b==0)return a;
else return gcd(b,a%b);
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
3. 质数
1. \(O(\sqrt{n})\)判断单个数是否是质数
bool isprime(int xx)
{
if(xx<2)return 0;
int limit=sqrt(xx);
for(int i=2;i<=limit;++i)
if(xx%i==0)
return 0;
return 1;
}
2. \(O(n)\)线性筛质数
int v[1000010],prime[1000010];
void linearprime(int n)
{
memset(v,0,sizeof(v));
int cnt=0;
for(int i=2;i<=n;i++)
{
if(v[i]==0)
{
v[i]=i;
prime[++cnt]=i;
}
for(int j=1;j<=cnt;j++)
{
if(prime[j]>v[i]||prime[j]>n/i)break;
v[i*prime[j]]=prime[j];
}
}
return;
}
3. Miller-Rabin 判素
4. \(O(\sqrt{n})\)分解质因数
int mp[1000010];
void factorization(int xx)
{
if(xx<2)return;
int limit=sqrt(xx);
for(int i=2;i<=limit;i++)
while(xx%i==0)
{
mp[i]++;
xx/=i;
if(xx==1)return;
}
if(xx>1)mp[xx]++;
return;
}
5. Pollard-Rho 分解质因数
5. 扩展欧几里得\(O(\log \max(a,b))\)
1. 板子
void exgcd(int a,int b,int &x,int &y)
{
if(!b){x=1;y=0;return;}
exgcd(b,a%b,y,x);
y-=a/b*x;
return;
}
2. 解形如\(ax+by=c\)的二元一次不定方程
6. 乘法逆元
1. 单个数求逆元\(O(\log \max(a,b))\)
int getinv(int a,int b)
{
int x,y;
exgcd(a,b,x,y);
return (x+b)%b;
}
2. \(O(n)\)求\(1,2,...,n\mod p\)的逆元
int inv[10000010];
void linearinv(int n,int p)
{
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=(long long)(p-p/i)*inv[p%i]%p;
return;
}
3. \(O(a+\log b)\)求\(1!,2!,...,a!\mod b\)的逆元
int facinv[10000010];
void getfacinv(int a,int b)
{
int now=1;
for(int i=1;i<=a;i++)now=now*i%b;
facinv[a]=getinv(now,b);
for(int i=a-1;i>=1;i--)facinv[i]=facinv[i+1]*(i+1)%b;
return;
}
7. 欧拉函数
1. 求单个\(\varphi (n)\quad O(\sqrt{n})\)
int geteuler(int n)
{
if(n==1)return 0;
int limit=sqrt(n),ans=n;
for(int i=2;i<=limit;i++)
if(n%i==0)
{
ans-=ans/i;
while(n%i==0)n/=i;
}
if(n>1)ans-=ans/n;
return ans;
}
2. \(O(n)\)求\(\varphi (1),\varphi (2),...,\varphi (n)\)
int v[1000010],prime[1000010],phi[1000010];
void lineareuler(int n)
{
memset(v,0,sizeof(v));
int cnt=0;
for(int i=2;i<=n;i++)
{
if(v[i]==0)
{
v[i]=i;
prime[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt;j++)
{
if(prime[j]>v[i]||prime[j]>n/i)break;
v[i*prime[j]]=prime[j];
phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
}
}
return;
}
8. CRT&exCRT
1. CRT
int crt()
{
int mul=1ll,ans=0;
for(int i=1;i<=n;i++)mul*=a[i];
for(int i=1;i<=n;i++)
{
int now=mul/a[i];
ans=(ans+now*inv(now,a[i])*b[i])%mul;
}
return (ans+mul)%mul;
}
2.exCRT
p.s. luogu的exCRT模板太过毒瘤,请使用光速乘
所有的int请自动理解为long long
int n,ans,lc=1,a[100010],b[100010];
inline int excrt()
{
int p,q,g,now,m;
for(int i=1;i<=n;i++)
{
exgcd(lc,a[i],p,q);
now=((b[i]-ans)%a[i]+a[i])%a[i];
g=gcd(lc,a[i]),m=a[i]/g;
if(now%g)return -1;
p=mul(now/g,p,m);
q=lc,lc*=m;
ans=(ans+mul(p,q,lc))%lc;
}
return ans;
}
9. Lucas&exLucas
虽然这两个东西是用来求组合数的,但鉴于具体计算还是与数论有关就放到这里了(
1. Lucas
int facs[100010];
int c(int n,int m,int p)
{
if(n>m)return 0;
return (qpow(facs[m-n],p-2,p)*qpow(facs[n],p-2,p)%p*facs[m])%p;
}
int lucas(int n,int m,int p)
{
if(m==0)return 1;
return c(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}