最大公约数与最小公倍数
int gcd(int a,int b)
{
int r=a%b;
while(r!=0)
{
a=b;
b=r;
r=a%b;
}
return b;
}
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}
快速幂&快速积
快速积的主要作用是防止乘数过大,炸 long long 范围
int Multiply(int a,int b)
{
int ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%Mod;
a=(a+a)%Mod;
b>>=1;
}
return ans;
}
int Power(int a,int b)
{
int ans=1;
while(b)
{
if(b&1)
ans=Multiply(ans,a);
a=Multiply(a,a);
b>>=1;
}
return ans;
}
线性筛
是素数集, 是最大质因数, 是最小质因数, 是欧拉函数, 是标记一个数是否为素数
int prime[N],Max[N],Min[N],phi[N];
bool mark[N];
void linear_sieves()
{
int i,j,sum=0;
memset(mark,true,sizeof(mark));
mark[0]=mark[1]=false;phi[1]=1;
for(i=2;i<N;++i)
{
if(mark[i])
{
phi[i]=i-1;
prime[++sum]=i;
Min[i]=Max[i]=i;
}
for(j=1;j<=sum&&i*prime[j]<N;++j)
{
mark[i*prime[j]]=false;
Max[i*prime[j]]=Max[i];
Min[i*prime[j]]=prime[j];
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
质因数分解
这个要用到线性筛素数( 是筛出的素数个数)
听说复杂度是 (因为 以内的素数约有 个,所以 内就有 个,而 ),不过只用记住它比较小就行了
void divide(int x)
{
int i;
for(i=1;i<=sum&&prime[i]*prime[i]<=x;++i)
{
while(x%prime[i]==0)
{
x/=prime[i];
printf("%d ",prime[i]);
}
}
if(x!=1) printf("%d",x);
}
扩展欧几里得
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;
}
逆元
快速幂(要求模数必须为质数)
inv 是逆元,x 是要求逆元的数,Power是快速幂,Mod 是模数
inv=Power(x,Mod-2);
扩展欧几里得(要求 x 必须与 Mod 互质)
exgcd(x,Mod,inv,y);
inv=(inv+Mod)%Mod;
Ps:快速幂和扩欧的模板就去上面看啦
线推
inv[1]=1;
for(i=2;i<=n;++i)
inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
组合数
递推组合数(方便取模)
C[n][m] 表示
C[0][0]=1;
for(i=1;i<=n;++i)
{
C[i][0]=1;
for(j=1;j<=i;++j)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%Mod;
}
线性筛出阶乘和逆元, 求组合数(Power 是快速幂,求逆元用的)
是阶乘, 是阶乘的逆元
void init()
{
int i;
fac[0]=fac[1]=1;
for(i=2;i<=n;++i) fac[i]=1ll*fac[i-1]*i%Mod;
inv[n]=Power(fac[n],Mod-2);
for(i=n-1;i>=1;--i) inv[i]=1ll*inv[i+1]*(i+1)%Mod;
}
int C(int n,int m)
{
return 1ll*fac[n]*inv[m]%Mod*inv[n-m]%Mod;
}
高斯消元
a[i][1]~a[i][n] 是各个元的系数, a[i][n+1] 是该计算出来的值
void Guass()
{
int i,j,k;
for(i=1;i<=n;++i)
{
k=i;
for(j=i+1;j<=n;++j)
if(fabs(a[k][i])<fabs(a[j][i]))
k=j;
swap(a[i],a[k]);
for(j=i+1;j<=n;++j)
for(k=i+1;k<=n+1;++k)
a[j][k]-=a[i][k]*a[j][i]/a[i][i];
}
for(i=n;i;--i)
{
for(j=i+1;j<=n;++j)
a[i][n+1]-=ans[j]*a[i][j];
ans[i]=a[i][n+1]/a[i][i];
}
}
矩阵快速幂
这里就把大致的框架打出来(代码中是 的矩阵)
struct matrix
{
int m[N][N];
matrix(int t=0)
{
memset(m,0,sizeof(m));
for(int i=1;i<=2;++i) m[i][i]=t;
}
friend matrix operator * (const matrix &a,const matrix &b)
{
int i,j,k;
matrix c(0);
for(i=1;i<=2;++i)
for(j=1;j<=2;++j)
for(k=1;k<=2;++k)
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
return c;
}
friend matrix operator ^ (matrix a,long long b)
{
matrix c(1);
for(;b;b>>=1,a=a*a)
if(b&1)
c=c*a;
return c;
}
};
康拓展开
康拓展开和逆康拓展开( 是预处理出来的阶乘)
ll cantor()
{
ll ans=0;
for(int i=1;i<=n;++i)
{
int num=0;
for(int j=i+1;j<=n;++j)
if(a[j]<a[i]) num++;
ans+=fac[n-i]*num;
}
return ans;
}
void reverse_cantor(ll x)
{
int i,j;x--;
memset(vis,false,sizeof(vis));
for(i=1;i<=n;++i)
{
int num=x/fac[n-i];
for(j=1;j<=n;++j)
if(!vis[j]&&!num--)
break;
a[i]=j;
vis[j]=true;
x%=fac[n-i];
}
}