数学部分
数论
整合包
#define LL long long
inline LL mul(LL a,LL b,LL mod){LL ans=0;while(b){if(b&1)ans=(ans+a)%mod;a=(a+a)%mod;b>>=1;}return ans;}
inline LL pow_mul(LL a,LL b,LL mod){LL ans=1;while(b){if(b&1)ans=mul(ans,a,mod);b>>=1;a=mul(a,a,mod);}return ((ans%mod)+mod)%mod;}
inline LL poww(LL a,LL b,LL mod){LL ans=1;while(b){if(b&1)ans=ans*a%mod;b>>=1;a=a*a%mod;}return ((ans%mod)+mod)%mod;}
LL gcd(LL a,LL b){if(!b)return a;return gcd(b,a%b);}
inline LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
void exgcd(LL a,LL b,LL &x,LL &y){if(!b){x=1,y=0;return ;}exgcd(b,a%b,y,x);y-=a/b*x;}
inline LL inv_gcd(LL num,LL mod){LL x=0,y=0;exgcd(num,mod,x,y);return ((x%mod)+mod)%mod;}
inline LL inv_pow(LL num,LL mod){return poww(num,mod-2,mod);}
LL get_elr(LL x){LL res=x;for(register int i=2;i*i<=x;i++){if(!(x%i)){res-=res/i;while(!(x%i))x/=i;}}if(x>1)res-=res/x;return res;}
LL CRT(int n,LL a[],LL m[],LL M){LL ans=0;for(register int i=1;i<=n;i++){LL mp=M/m[i];x=0,y=0;exgcd(mp,m[i],x,y);ans=((ans+a[i]*mp*x)%M+M)%M;}return ans;}
LL ex_CRT(int n,LL *a,LL *m){int flag=1;for(register int i=2;i<=n;i++){LL M1=m[i-1],M2=m[i];LL A1=a[i-1],A2=a[i],d=gcd(M1,M2);if((A2-A1)%d){flag=0;break;}m[i]=M1/d*M2;a[i]=(((inv_gcd(M1/d,M2/d)*(A2-A1)/d)%(M2/d)*M1+A1)%m[i]+m[i])%m[i];}return flag?a[n]:-1;}
void sieve(int n,int pri[],int vis[],int &tot){vis[1]=1;for(register int i=2;i<=n;i++){if(!vis[i])pri[++tot]=i;for(register int j=1;i*pri[j]<=n;j++){if(!(i%pri[j]))break;vis[i*pri[j]]=1;}}}
void sieve_elr(int n,int phi[],int pri[],int vis[],int &tot){phi[1]=vis[1]=1;for(register int i=2;i<=n;i++){if(!vis[i]){pri[++tot]=i;phi[i]=i-1;}for(register int j=1;i*pri[j]<=n;j++){if(!(i%pri[j])){vis[i*pri[j]]=1;phi[i*pri[j]]=phi[i]*pri[j];break;}vis[i*pri[j]]=1;phi[i*pri[j]]=phi[i]*(pri[j]-1);}}}
快速乘
inline LL mul(LL a,LL b,LL mod)
{
LL ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%mod;
a=(a+a)%mod;b>>=1;
}
return ans;
}
快速幂
inline LL poww(LL a,LL b,LL mod)
{
LL ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
gcd,最大公因数,欧几里得算法
LL gcd(LL a,LL b)
{
if(!b)
return a;
return gcd(b,a%b);
}
lcm,最小公倍数
inline LL lcm(LL a,LL b)
{
return a/gcd(a,b)*b;
}
exgcd,扩展欧几里得
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
求逆元(单个)
inline LL inv_gcd(LL num,LL mod)//拓展欧几里得
{
LL x=0,y=0;exgcd(num,mod,x,y);
return ((x%mod)+mod)%mod;
}
inline LL inv_pow(LL num,LL mod)//费马小定理
{
return poww(num,mod-2,mod);
}
求欧拉函数(单个)
LL get_elr(LL x)
{
LL res=x;
for(register int i=2;i*i<=x;i++)
{
if(!(x%i))
{
res-=res/i;
while(!(x%i))
x/=i;
}
}
if(x>1)
res-=res/x;
return res;
}
线性筛
void sieve(int n,int pri[],int vis[],int &tot)
{
vis[1]=1;
for(register int i=2;i<=n;i++)
{
if(!vis[i])
pri[++tot]=i;
for(register int j=1;i*pri[j]<=n;j++)
{
if(!(i%pri[j]))
break;
vis[i*pri[j]]=1;
}
}
}
欧拉筛
void sieve_elr(int n,int phi[],int pri[],int vis[],int &tot)
{
phi[1]=vis[1]=1;
for(register int i=2;i<=n;i++)
{
if(!vis[i])
{
pri[++tot]=i;
phi[i]=i-1;
}
for(register int j=1;i*pri[j]<=n;j++)
{
if(!(i%pri[j]))
{
vis[i*pri[j]]=1;
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
vis[i*pri[j]]=1;
phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
}
CRT,中国剩余定理
LL CRT(int n,LL a[],LL m[],LL M)
{
LL ans=0;
for(register int i=1;i<=n;i++)
{
LL mp=M/m[i];
x=0,y=0;
exgcd(mp,m[i],x,y);
ans=((ans+a[i]*mp*x)%M+M)%M;
}
return ans;
}
exCRT,扩展中国剩余定理
LL ex_CRT(int n,LL *a,LL *m)
{
int flag=1;
for(register int i=2;i<=n;i++)
{
LL M1=m[i-1],M2=m[i];
LL A1=a[i-1],A2=a[i],d=gcd(M1,M2);
if((A2-A1)%d)
{
flag=0;
break;
}
m[i]=M1/d*M2;
a[i]=(((inv_gcd(M1/d,M2/d)*(A2-A1)/d)%(M2/d)*M1+A1)%m[i]+m[i])%m[i];
}
return flag?a[n]:-1;
}
矩阵
矩阵快速幂
struct matrix
{
LL a[101][101]={};
inline void build()
{
for(register int i=1;i<=n;i++)
a[i][i]=1;
}
}a;
matrix operator *(const matrix &x,const matrix &y)
{
matrix z;
for(register int k=1;k<=n;++k)
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
return z;
}
inline matrix poww(matrix x,LL k)
{
matrix res;
res.build();
while(k)
{
if(k&1)
res=res*x;
x=x*x;
k>>=1;
}
return res;
}