【模板】数学
同余
逆元
线性递推
inv[1]=1;
for(int i=2;i<=n;++i) inv[i]=p-inv[p%i]*(p/i)%p,inv[i]%=p;
快速幂
inv[i]=ksm(i,p-2,p)
阶乘递推
inv[n]=ksm(po[n],p-2,p);//po[i]是i的阶乘
for(int i=n-1;i;--i) inv[i]=inv[i+1]*(i+1)%p;
高次同余方程
大小步(BSGS)
点击查看代码
int bsgs(int a,int b,int p){//(a^x)%p=b%p
map<int,int> ha;
int t=sqrt(p)+1;
for(int i=0,q=b%p;i<t;++i,q=q*a%p) ha[q]=i;
int w=ksm(a,t,p);
for(int i=1,q=w;i<=t;++i,q=q*w%p)
if(ha.find(q)!=ha.end()) return t*i-ha[q];
return -1;
}
拓展大小步(EX-BSGS)
点击查看代码
int bsgs(int a,int b,int p,int ad){
unordered_map<int,int> ha;
int t=sqrt(p)+1;
for(int i=0,j=b%p;i<t;++i,j=j*a%p) ha[j]=i;
int w=ksm(a,t,p);
for(int i=1,j=ad*w%p;i<=t;++i,j=j*w%p)
if(ha.find(j)!=ha.end()) return i*t-ha[j];
return -1;
}
int exbsgs(int a,int b,int p){
a%=p,b%=p;
int cnt=0,ad=1,t;
if(b==1 || p==1) return 0;
while((t=__gcd(a,p))!=1){
if(b%t!=0) return -1;
++cnt,b/=t,p/=t,ad=ad*(a/t)%p;
if(ad==b) return cnt;
}
t=bsgs(a,b,p,ad);return (t==-1?-1:t+cnt);
}
中国剩余定理
CRT
点击查看代码
int CRT(){
int m=1,res=0,x,y;
for(int i=1;i<=n;++i) m*=a[i];
for(int i=1;i<=n;++i){
int tmp=m/a[i];
exgcd(tmp,a[i],x,y);
res=(res+tmp*x*b[i]%m)%m;
}
return (res%m+m)%m;
}
EX-CRT
点击查看代码
const int N=1e5+5;
int a[N],b[N],n;
int exgcd(int a,int b,int &x,int &y){
if(!b){x=1,y=0;return a;}
int g=exgcd(b,a%b,x,y),t=x;
x=y,y=t-a/b*y;
return g;
}
int excrt(){
int A=a[1],B=b[1];
for(int i=2;i<=n;++i){
int k1,k2;
int g=exgcd(A,a[i],k1,k2);
if((b[i]-B)%g!=0) return -1;
k1*=(b[i]-B)/g;
k1=(k1%(a[i]/g)+(a[i]/g))%(a[i]/g);
B=k1*A+B,A=(A*a[i])/g;
}
return B%A;
}
欧拉定理
拓展欧拉定理
注意快读写法!
记住!\(n\) 小于 \(\phi(p)\) 的时候不能加 \(\phi(p)\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int cnt=0;
namespace IOBuf{
char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int read(int p){
int sum=0,f=1;char a=gc();cnt=0;
while(a<'0' || a>'9'){if(a=='-')f=-1;a=gc();}
while(a>='0' && a<='9') sum=sum*10+a-'0',cnt|=(sum>=p),sum%=p,a=gc();
return (sum*f%p+p)%p;
}
void print(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(char(48+x%10));
}
}
using namespace IOBuf;
int ksm(int x,int y,int p){
int res=1;
while(y){if(y&1)res=res*x%p;y>>=1,x=x*x%p;}
return res%p;
}
signed main(){
int a=read((int)1e10),p=read((int)1e10),n;
int pi=1;int t=p;
for(int i=2;i*i<=p;++i){
if(p%i!=0) continue;
pi*=(i-1),p/=i;while(p%i==0)pi*=i,p/=i;
}
if(p>1) pi*=(p-1);
n=read(pi);
if(cnt) n+=pi;
print(ksm(a,n,t));
return 0;
}
线性代数
消元
高斯消元
点击查看代码
void Guass(){
for(int i=1;i<=n;++i){
int ma=i;
for(int j=i+1;j<=n;++j)if(fabs(a[j][i])>fabs(a[ma][i]))ma=j;
if(i!=ma) swap(a[i],a[ma]);
if(fabs(a[i][i])<eps){cout<<"No Solution\n";return;}
d div=a[i][i];
for(int j=i;j<=n+1;++j) a[i][j]/=div;
for(int j=i+1;j<=n;++j){
div=a[j][i];
for(int k=i;k<=n+1;++k) a[j][k]-=div*a[i][k];
}
}
for(int i=n;i;--i){
ans[i]=a[i][n+1];
for(int j=i-1;j;--j)a[j][n+1]-=(a[j][i]*ans[i]);
}
for(int i=1;i<=n;++i)printf("%.2lf\n",ans[i]);
}
高斯-约旦 消元
点击查看代码
void Guass_Jordan(){
for(int i=1;i<=n;++i){
int ma=i;
for(int j=i+1;j<=n;++j)if(fabs(a[j][i])>fabs(a[ma][i]))ma=j;
for(int j=1;j<=n+1;++j)swap(a[i][j],a[ma][j]);
// cout<<ma<<" : ";
if(fabs(a[i][i])<eps){cout<<"No Solution";return;}
for(int j=1;j<=n;++j){
if(j==i) continue;
for(int k=i+1;k<=n+1;++k)a[j][k]-=a[i][k]*a[j][i]/a[i][i];
}
}
for(int i=1;i<=n;++i)printf("%.2lf\n",a[i][n+1]/a[i][i]);
}
约数
拓展欧几里得定理(exgcd)
点击查看代码
int exgcd(int a,int b,int &x,int &y){
if(!b){x=1,y=0;return a;}
int g=exgcd(b,a%b,x,y),t=x;
x=y,y=t-a/b*y;
return g;
}
线性筛法求欧拉函数
点击查看代码
void init(int n){
for(int i=2;i<=n;++i){
if(!vi[i]) pr[++co]=i,phi[i]=i-1;
for(int j=1;j<=co && i*pr[j]<=n;++j){
vi[pr[j]*i]=1;
if(i%pr[j]==0){
phi[pr[j]*i]=phi[i]*pr[j];
break;
}
else phi[i*pr[j]]=phi[i]*(pr[j]-1);
}
}
}