一些奇怪的模板
数学
快速幂
long long版
PS:如果传入参数是long long请自行修改
typedef long long LL; LL qmi(int a,int b,int q) { LL ans=1%q; while(b) { if(b & 1) ans=ans*a%q; a=(LL)a*a%q; b>>=1; } return ans; }
int版
int qmi(int a,int b,int q) { int ans=1%q; while(b) { if(b & 1) ans=ans*a%q; a=a*a%q; b>>=1; } return ans; }
高精度运算
原地址:duoluoluo的博客-高精模板
数论
Gcd和Lcm
inline int gcd(int x,int y){ return y==0?x:gcd(y,x%y); }
inline int gcd(int x,int y){ return y==0?x:gcd(y,x%y); } inline long long lcm(int x,int y){ return 1ll*x/gcd(x,y)*y; }
线性筛法
int p[N],cnt; bool st[N]; int get_prime(int n) { for(int i=2;i<=n;i++) { if(!st[i]) p[++cnt]=i; for(int j=1;p[j]<=n/i;j++) { st[i*p[j]]=1; if(i%p[j]==0) break; } } }
线性筛法的求解欧拉函数
int prime[N],phi[N],cnt; bool st[N]; int get_phi(int n) { phi[1]=1; for(int i=2;i<=n;i++) { if(!st[i]) { prime[++cnt]=i; phi[i]=i-1; } for(int j=1;j<=cnt && prime[j]*i<=n;j++) { st[i*prime[j]]=1; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; } else phi[i*prime[j]]=phi[i]*phi[prime[j]]; } } }
线性筛法求解莫比乌斯函数
void get_mu(int n) { mu[1]=1; //定义1 for(int i=2;i<=n;i++) { if(!vis[i]){prim[++cnt]=i;mu[i]=-1;} //i是质数,则mu[i]=-1 for(int j=1;j<=cnt&&prim[j]*i<=n;j++) { vis[prim[j]*i]=1; //打标记 if(i%prim[j]==0)break; mu[i*prim[j]]=-mu[i]; } } }
数论分块
long long solve(int n) { long long sum=0,l,r; for(l=1;l<=n;l=r+1) { r=n/(n/l); sum+=(n/l)*(r-l+1); } return sum; }
进制转换
int x,n,tot=0,s[100]; scanf("%d %d",&n,&x); while (n!=0) { int a=n%x; n=n/x; s[++tot]=a; }
判断质数
bool prime(int x) { if(x<=1)return false; if(x==2)return true; for(int i=2;i<=sqrt(x);i++) if(!x%i) return false; return true; }
排序
快速排序
void qsort(int l,int r) { int i,j,mid,p; i=l; j=r; mid=a[(l+r)/2]; while(i<j) { while(a[i]<mid) { i++; } while(a[j]>mid) { j--; } if(i<=j) { p=a[i]; a[i]=a[j]; a[j]=p; i++; j--; } } if(l<j) { qsort(l,j); } if(i<r) { qsort(i,r); } }
归并排序
void msort(int l,int r) { if(l==r)return ; int mid=(l+r)/2; msort(l,mid); msort(mid+1,r); int i=l,j=mid+1,k=l; while(i<=mid && j<=r) { if(a[i]<=a[j]) { R[k]=a[i]; i++; k++; } else { R[k]=a[j]; j++; k++; } } while(i<=mid) { R[k]=a[i]; i++; k++; } while(j<=r) { R[k]=a[j]; j++; k++; } for(int i=l;i<=r;i++) { a[i]=R[i]; } }
逆序对1
void msort(int l,int r) { if(l==r)return ; int mid=(l+r)/2; msort(l,mid); msort(mid+1,r); int i=l,j=mid+1,k=l; while(i<=mid && j<=r) { if(a[i]<=a[j]) { R[k]=a[i]; i++; k++; } else { R[k]=a[j]; j++; k++; ans=ans+mid-i+1; } } while(i<=mid) { R[k]=a[i]; i++; k++; } while(j<=r) { R[k]=a[j]; j++; k++; } for(int i=l;i<=r;i++) { a[i]=R[i]; } }
逆序对2
#include<bits/stdc++.h> using namespace std; const int N=5e5+100; int n,a[N],lsh[N]; int c[N],cnt; inline int lowbit(int x){ return x&(-x); } inline void modify(int x){ for(;x<=n;x+=lowbit(x)) c[x]++; } inline int long long ask(int x){ long long res=0; for(;x>0;x-=lowbit(x)) res+=c[x]; return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),lsh[i]=a[i]; //离散化 sort(lsh+1,lsh+n+1); n=unique(lsh+1,lsh+n+1)-lsh-1; for(int i=1;i<=n;i++) a[i]=lower_bound(lsh+1,lsh+n+1,a[i])-lsh; long long ans=0; for(int i=1;i<=n;i++) { modify(a[i]); ans+=i-ask(a[i]); } printf("%lld",ans); return 0; }
冒泡排序
for(int i=1;i<=n;i++) for(int j=1;j<n-i;j++) if(array[j]>array[j+1]) swap(array[j],array[j+1];
桶排序
for(int i=1;i<=n;i++) { int tmp; scanf("%d",&tmp); a[tmp]++; } for(int i=0;i<=n;i++) for(int j=1;j<=a[i];j++) printf("%d ",i); //注:本排序仅支持正整数
动态规划
背包
01背包
for(int i=1;i<=m;i++) for(int j=t;j>=a[i];j--) f[j]=max(f[j],f[j-a[i]]+b[i]);
完全背包
for(int i=1;i<=m;i++) for(int j=a[i];j<=t;j++) f[j]=max(f[j],f[j-a[i]]+b[i]);
多重背包
for(int i=1;i<=n;++i) for(int j=V;j>=v[i];--j) f[j]=max(f[j],f[j-v[i]]+w[i]); for(int i=0;i<=V;++i)ans=max(ans,f[i]);
混合背包
注释:混合背包没有固定形态,这里提供以樱花为例的模板。
for(int i=1;i<=n;i++) { scanf("%d %d %d",&x,&y,&z); if(!z) //可以无限看 { d[++tot]=0; w[tot]=x; v[tot]=y; } else { for(int j=1;j<=z;j*=2) { d[++tot]=1; w[tot]=j*x; v[tot]=j*y; z-=j; } if(z) { d[++tot]=1; w[tot]=z*x; v[tot]=z*y; } } //二进制多重背包 } for(int i=1;i<=tot;i++) { if(d[i]) for(int j=last_time;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+v[i]); else for(int j=w[i];j<=last_time;j++) f[j]=max(f[j],f[j-w[i]]+v[i]); } }
树形DP
邻接表
int head[N],ver[M],Next[M],edge[M],tot; void add(int x,int y,int z) { ver[++tot]=y; edge[tot]=z; Next[tot]=head[x]; head[x]=tot; }
一般的树形DP
void dp(int x) { f[x][0]=0; f[x][1]=h[x]; int len=son[x].size(); for(int i=0;i<len;i++) { int y=son[x][i]; dp(y); f[x][0]+=max(f[y][0],f[y][1]); f[x][1]+=f[y][0]; } }
树形DP-背包
以选课为例
void dp(int x) { f[x][0]=0; int len=son[x].size(); for(int i=0;i<len;i++) { int y=son[x][i]; dp(y); for(int j=m;j>=0;j--) for(int t=j;t>=0;t--) f[x][j]=max(f[x][j],f[x][j-t]+f[y][t]); } if(x!=0) { for(int t=m;t>=1;t--) { f[x][t]=f[x][t-1]+s[x]; } } }
换根DP-积蓄程度
void dp(int x) { v[x]=1; d[x]=0; for(int i=head[x];i;i=Next[i]) { int y=ver[i]; if(v[y]) continue; dp(y); if(deg[y]==1) d[x]+=edge[i]; else d[x]+=min(d[y],edge[i]); } } void dfs(int x) { v[x]=1; for(int i=head[x];i;i=Next[i]) { int y=ver[i]; if(v[y]) continue; if(deg[x]==1) f[y]+=d[y]+edge[i]; else f[y]=d[y]+min(f[x]-min(d[y],edge[i]),edge[i]); dfs(y); } }
状压DP
最短Hamilton路径
memset(f,0x3f,sizeof(f)); f[1][0]=0; for(int i=0;i<(1<<n);i++) { for(int j=0;j<n;j++) { if((i>>j) & 1) { for(int k=0;k<n;k++) { if((i>>k) & 1) { f[i][j]=min(f[i][j],f[i-(1<<j)][k]+a[k][j]); } } } } } printf("%d",f[(1<<n)-1][n-1]);
蒙德里安的梦想
for(int i=0;i<1<<n;i++) { int cnt=0; st[i]=true; for(int j=0;j<n;j++) { if(i>>j & 1) { if(cnt & 1) st[i]=false; cnt=0; } else cnt++; } if(cnt & 1) st[i]=false; } memset(f,0,sizeof(f)); f[0][0]=1; for(int i=1;i<=m;i++) for(int j=0;j<1<<n;j++) for(int k=0;k<1<<n;k++) if(!(j & k) && st[j | k]) f[i][j]+=f[i-1][k]; printf("%lld\n",f[m][0]);
单调栈
单调递增栈
for(int i=1;i<=n;i++) { int x; scanf("%d",&x); while(tot>0 && x>sta[tot][0]) { ans[sta[tot][1]]=i; tot--; } sta[++tot][0]=x,sta[tot][1]=i; }
单调递减栈
for(int i=1;i<=n;i++) { int x; scanf("%d",&x); while(tot>0 && x<sta[tot][0]) { ans[sta[tot][1]]=i; tot--; } sta[++tot][0]=x,sta[tot][1]=i; }
单调队列
单调递增队列
for(int i=0;i<n;i++) { if(hh<=tt && i-q[hh]+1>k) hh++; while(hh<=tt && a[q[tt]]>=a[i]) tt--; q[++tt]=i; if(i>=k-1) printf("%d ",a[q[hh]]); }
单调递减队列
for(int i=0;i<n;i++) { if(hh<=tt && i-q[hh]+1>k) hh++; while(hh<=tt && a[q[tt]]<=a[i]) tt--; q[++tt]=i; if(i>=k-1) printf("%d ",a[q[hh]]); }
搜索
全排列类问题
void dfs(int x) { if(x==n+1) { for(int i=1;i<=n;i++) { printf("%5d",a[i]); } cout<<endl; return; } for(int i=1;i<=n;i++) { if(!st[i]) { st[i]=true; a[x]=i; dfs(x+1); st[i]=false; } } }
平面移动类问题
以回家为例
int fx[4]={1,-1,0,0},fy[4]={0,0,1,-1}; void dfs(int x,int y,int z) { z--; if(hp==0||ss>n*m||ss>s) { return; } if(a[x][y]==4) { z=6; } if(x==h1&&y==h2) { u=0; s=min(ss,s); return; } for(int i=0;i<4;i++) { if(a[x+fx[i]][y+fy[i]]!=0&&x+fx[i]>=0&&x+fx[i]<n&&y+fy[i]>=0&&y+fy[i]<m) { ss++; dfs(x+fx[i],y+fy[i],z-1); ss--; } } }
一些关于树的其他东西
遍历
中序、前序求后序
void dfs(int L1,int R1,int L2,int R2) { int m=a.find(b[L2]); if(m>L1) { dfs(L1,m-1,L2+1,m+L2-L1); } if(m<R1) { dfs(m+1,R1,R2-R1+m+1,R2); } cout<<a[m]; }
中序、后序求前序
void dfs(int L1,int R1,int L2,int R2) { int m=a.find(b[R2]); cout<<a[m]; if(m>L1) { dfs(L1,m-1,L2,m+L2-L1-1); } if(m<R1) { dfs(m+1,R1,R2-R1+m,R2-1); } }
树的直径
DP做法
void dp(int x) { v[x]=1; for(int i=head[x];i;i=Next[i]) { int y=ver[i]; if(v[y]) continue; dp(y); ans=max(ans,d[x]+d[y]+edge[i]); d[x]=max(d[x],d[y]+edge[i]); } }
2次BFS做法
int bfs(int x) { queue<int> q; while(!q.empty()) { q.pop(); } memset(v,0,sizeof(v)); memset(dis,0,sizeof(dis)); memset(fa,0,sizeof(fa)); q.push(x); int k,max_num,MAX=0; while(q.size()) { k=q.front(); q.pop(); v[k]=1; for(int i=head[k];i>=1;i=Next[i]) { int y=ver[i]; if(v[y]) { continue; } v[y]=1; fa[y]=k; dis[y]=dis[k]+edge[i]; if(dis[y]>MAX) { MAX=dis[y]; max_num=y; } q.push(y); } } return max_num; }
线段树
建树
struct segmenttree{ int l,r,sum; }; segmenttree a[4*N+1]; void build(int p,int l,int r) { a[p].l=l,a[p].r=r; if(l==r) { a[p].sum=b[l]; return ; } int mid=a[p].l+a[p].r>>1; build(p*2,l,mid); build(p*2+1,mid+1,r); a[p].sum=a[p*2].sum+a[p*2+1].sum; }
单点修改
void rebuild_node(int p,int x,int k) { if(a[p].l==a[p].r) { a[p].sum+=k; return ; } int mid=a[p].l+a[p].r>>1; if(x<=mid) rebuild_node(p*2,x,k); else rebuild_node(p*2+1,x,k); a[p].sum=a[p*2].sum+a[p*2+1].sum; }
询问
int ask(int p,int l,int r) { int ans=0,mid=a[p].l+a[p].r>>1; if(a[p].l>=l && a[p].r<=r) { ans+=a[p].sum; return ans; } if(l<=mid) ans+=ask(p*2,l,r); if(r>mid) ans+=ask(p*2+1,l,r); return ans; }
图论
单源最短路SPFA
void SPFA() { d[s]=0; v[s]=1; q.push(s); while(q.size()) { int x=q.front(); q.pop(); v[x]=0; for(int i=head[x];i;i=Next[i]) { int y=ver[i],z=edge[i]; if(d[y]>d[x]+z) { d[y]=d[x]+z; if(!v[y]) { v[y]=1; q.push(y); } } } } }
单源最短路Dijkstra
const int N=101000,M=5e5+1; int ver[M],head[N],Next[M],tot,edge[M],d[N],v[N]; int n,m,s; priority_queue<pair <int,int> > q; void add(int x,int y,int z) { ver[++tot]=y; edge[tot]=z; Next[tot]=head[x]; head[x]=tot; } void dijkstra(int k) { memset(v,0,sizeof(v)); d[k]=0; q.push(make_pair(0,k)); while(q.size()) { int x=q.top().second; q.pop(); if(v[x]) continue; v[x]=1; for(int i=head[x];i;i=Next[i]) { int y=ver[i],z=edge[i]; if(d[y]>d[x]+z) { d[y]=d[x]+z; q.push(make_pair(-d[y],y)); } } } }
多源最短路Floyd
for(int i=1;i<=N;i++){ for(int j=1;j<=N;j++) f[i][j]=MAXX; f[i][i]=0; } ...//你的操作 for(int k=1;k<=N;k++) for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
Floyd的传递闭包变形
for(int k=1;k<=N;k++) for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) f[i][j] |= f[i][k] & f[k][j];
其它
区间DP的拆环操作
for(int i=1;i<=n;i++) { a[i+n]=a[i]; }
一维前缀和
for(int i=1;i<=n;i++) { w[i]+=w[i-1]+a[i]; }
二维前缀和初始化模板
for(int i=1;i<=5001;i++) for(int j=1;j<=5001;j++) a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+a[i][j];
二维前缀和累加模板
for(int i=m;i<=5001;i++) for(int j=m;j<=5001;j++) ans=max(ans,a[i][j]-a[i-m][j]-a[i][j-m]+a[i-m][j-m]);
快速输入1
inline int read() { int num=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') { num=(num<<1)+(num<<3)+ch-'0'; ch=getchar(); } return num; }
快速输入2
inline int in() { int f,t; f=1,t=0; char ch=getchar(); while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9') { t=t*10+ch-'0'; ch=getchar(); } return f*t; }
快速输出1
inline void quick_put(int x) { if(x==0) { printf("0"); return ; } char F[200]; int tmp=abs(x); if(x<0)putchar('-') ; int cnt=0; while(tmp>0) { F[cnt++]=tmp%10+'0'; tmp/=10; } while(cnt>0) putchar(F[--cnt]) ; }
快速输出2
putchar(x+'0');
二分1
long long l=0,r=N; while(l<r) { long long mid=l+r+1>>1; if(check(mid)) l=mid; else r=mid-1; }
二分2
long long l=0,r=N; while(l<r) { long long mid=l+r>>1; if(check(mid)) r=mid; else l=mid+1; }
manachar算法
char s[N<<1],a[N<<1]; int p[N],n,le,k,cnt[N],ans=1,tot; void read(){ scanf("%s",a+1); //n=strlen(a); s[0]='~',s[1]='#'; for(int i=1;i<=le;i++)s[i*2-1]='#',s[i*2]=a[i]; le=le*2+1,s[le]='#'; } void mnc(){ read(); int maxr=0,mid=0; for(int i=1;i<=le;i++){ if(i<maxr)p[i]=min(maxr-i,p[mid*2-i]); else p[i]=1; for(;s[p[i]+i]==s[i-p[i]];++p[i]); if(p[i]+i>maxr)maxr=p[i]+i,mid=i; } }