基础
对拍程序
转自http://blog.csdn.net/wlx65003/article/details/51149196
@echo off
:loop
rand.exe > in.txt
my.exe < in.txt > myout.txt
std.exe < in.txt > stdout.txt
fc myout.txt stdout.txt
if not errorlevel 1 goto loop
pause
goto loop
快速幂
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll x,y,m;
ll qsm(ll x,ll y,ll m)
{
ll ret=1;
x%=m;
while (y)
{
if (y&1) ret*=x;
ret%=m,x*=x,x%=m,y/=2;
}
return ret;
}
int main()
{
scanf("%lld%lld%lld",&x,&y,&m),printf("%lld",qsm(x,y,m));
}
读入优化
必备技巧
inline void read(int &x)
{
x=0;
int f=1;
char ch=getchar();
while (!isdigit(ch))
{
if (ch=='-') f=-1;
ch=getchar();
}
while (isdigit(ch))
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
x*=f;
}
二分
推荐两个函数:lower_bound&upper_bound(具体用法不再解释)
对于线性递增的数组,x值的位置下界为lower_bound(a+1,a+n+1,x)-a,上界为upper_bound(a+1,a+n+1,x)-a-1;
求下界:
void binary_find()
{
l=1,r=INF;
while (l!=r)
{
int mid=(l+r)/2;
if (check(mid)) r=mid;else l=mid+1;
}
}
求上界:(注意细节)
void binary_find()
{
l=1,r=INF;
while (l!=r)
{
int mid=(l+r+1)/2;
if (check(mid)) l=mid;else r=mid-1;
}
}
线性筛
时间复杂度仅为O(n)。
筛质数:
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 10000050
using namespace std;
int f[maxn],p[maxn],top=0,i,j,n;
int main()
{
scanf("%d",&n),f[0]=f[1]=1,p[0]=0;
for (i=2;i<=n;i++)
{
if (f[i]==0) p[++top]=i;
for (j=1;j<=top&&i*p[j]<=n;j++)
{
f[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
printf("%d\n",top);
for (i=1;i<=top;i++) printf("%d ",p[i]);
}
筛 ϕ \phi ϕ:
#include<bits/stdc++.h>
#define N 1000050
using namespace std;
int prime[N],p[N],n,tot=0,phi[N];
int main()
{
scanf("%d",&n),phi[1]=1;
for (int i=2;i<n;i++)
{
if (!p[i]) prime[++tot]=i,phi[i]=i-1;
for (int j=1;j<=tot&&i*prime[j]<n;j++)
{
p[i*prime[j]]=1;
if (i%prime[j]==0) {phi[i*prime[j]]=phi[i]*prime[j];break;}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for (int i=1;i<=tot;i++) printf("%d\n",prime[i]);
for (int i=1;i<=n;i++) printf("%d\n",phi[i]);
}
筛 μ \mu μ:
#include<bits/stdc++.h>
#define N 1000050
using namespace std;
int prime[N],p[N],n,tot=0,mu[N];
int main()
{
scanf("%d",&n),mu[1]=1;
for (int i=2;i<n;i++)
{
if (!p[i]) prime[++tot]=i,mu[i]=-1;
for (int j=1;j<=tot&&i*prime[j]<n;j++)
{
p[i*prime[j]]=1;
if (i%prime[j]==0) {mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=-mu[i];
}
}
for (int i=1;i<=tot;i++) printf("%d\n",prime[i]);
for (int i=1;i<=n;i++) printf("%d\n",mu[i]);
}
图论
邻接表
有很多种写法,强烈安利我的这种写法,操作简单、便捷。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100050
#define add(u,v,vv) to[++top]=head[u],head[u]=top,w[top]=v,val[top]=vv
#define For(x) for(int h=head[x],o=w[h],v=val[h];h;o=w[h=to[h]],v=val[h])
using namespace std;
int n,m,i,top=0,head[maxn*2],to[maxn*2],w[maxn*2],val[maxn*2],u,v,vv;
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++) scanf("%d%d%d",&u,&v,&vv),add(u,v,vv);
for (i=1;i<=n;i++) For(i) printf("%d to %d:%d\n",i,o,v);
}
LCA
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100050
#define add(u,v) to[++top]=head[u],head[u]=top,w[top]=v
#define For(x) for(int h=head[x],o=w[h];h;o=w[h=to[h]])
using namespace std;
int n,q,u,v,i,top=0,f[maxn][25],d[maxn],head[maxn*2],to[maxn*2],w[maxn*2];
inline void dfs(int x,int fa)
{
d[x]=d[fa]+1;
for (i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1];
For(x) if (o!=fa) f[o][0]=x,dfs(o,x);
}
inline int lca(int u,int v)
{
if (d[u]<d[v]) swap(u,v);
for (int i=20;i>=0;i--)
{
if (d[f[u][i]]>=d[v]) u=f[u][i];
if (u==v) return u;
}
for (int i=20;i>=0;i--) if (f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][0];
}
int main()
{
scanf("%d%d",&n,&q);
for (i=1;i<n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
dfs(1,0);
while (q--) scanf("%d%d",&u,&v),printf("%d",lca(u,v));
}
SPFA
队列优化的bfs,时间复杂度O(km)(k约等于2)。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100050
#define add(u,v,vv) to[++top]=head[u],head[u]=top,w[top]=v,val[top]=vv
#define For(x) for(int h=head[x],o=w[h],v=val[h];h;o=w[h=to[h]],v=val[h])
using namespace std;
int top=0,l,r,q[maxn*2],dis[maxn],bo[maxn],head[maxn],to[maxn],w[maxn],val[maxn],n,m,u,v,vv,s,t,x;
inline void spfa()
{
q[l=r=0]=s,memset(bo,0,sizeof(bo)),memset(dis,0x7f,sizeof(dis)),dis[s]=0,bo[s]=1;
while (l<=r)
{
x=q[l];
For(x) if (dis[x]+v<dis[o])
{
dis[o]=dis[x]+v;
if (!bo[o]) bo[o]=1,q[++r]=o;
}
l++,bo[x]=0;
}
}
int main()
{
scanf("%d%d",&n,&m);
while (m--) scanf("%d%d%d",&u,&v,&vv),add(u,v,vv);
scanf("%d%d",&s,&t),spfa(),printf("%d",dis[t]);
}
二分图匹配
#include<cstdio>
#include<algorithm>
#include<cstring>
#define add(u,v) to[++top]=head[u],head[u]=top,w[top]=v
#define For(x) for(int h=head[x],o=w[h];h;o=w[h=to[h]])
#define maxn 5050
using namespace std;
int top=0,to[maxn*maxn],head[maxn*maxn],w[maxn*maxn],t[maxn],vis[maxn],ans=0,n,m,e,u,v;
inline bool dfs(int x)
{
For(x) if (!vis[o])
{
vis[o]=1;
if (!t[o]||dfs(o)) {t[o]=x; return 1;}
}
return 0;
}
int main()
{
scanf("%d%d%d",&n,&m,&e);
while (e--)
{
scanf("%d%d",&u,&v);
if (u<=n&&v<=m) add(u,v);
}
for (int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if (dfs(i)) ans++;
}
printf("%d",ans);
}
网络流
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 10050
#define maxm 100050
#define INF 1000000000
#define add(u,v,vv) to[++top]=head[u],head[u]=top,w[top]=v,cap[top]=vv
#define For(x) for(int h=head[x],o=w[h];h;o=w[h=to[h]])
using namespace std;
int top=1,to[maxm*2],head[maxm*2],w[maxm*2],cap[maxm*2],level[maxn],q[maxn*8],l,r,s,t,x;
int n,m,u,v,vv;
inline bool bfs()
{
memset(level,0,sizeof(level));
q[l=r=0]=s,level[s]=1;
while (l<=r)
{
x=q[l++];
For(x) if (cap[h]&&level[o]==0) level[o]=level[x]+1,q[++r]=o;
}
return level[t];
}
inline int dfs(int x,int maxflow)
{
if (x==t||!maxflow) return maxflow;
int ret=0;
For(x) if (cap[h]&&level[o]==level[x]+1)
{
int tmp=dfs(o,min(cap[h],maxflow));
ret+=tmp,maxflow-=tmp,cap[h]-=tmp,cap[h^1]+=tmp;
}
if (!ret) level[x]=0;
return ret;
}
inline int dinic()
{
int ret=0;
while (bfs())
ret+=dfs(s,INF);
return ret;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for (int i=1;i<=m;i++) scanf("%d%d%d",&u,&v,&vv),add(u,v,vv),add(v,u,0);
printf("%d",dinic());
}
数据结构
并查集
不带权的版本
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 10050
using namespace std;
int f[maxn],n,m,u,v,opt;
inline int find(int x)
{
if (x==f[x]) return x;
f[x]=find(f[x]); return f[x];
}
inline void union_(int u,int v) {f[find(u)]=find(v);}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) f[i]=i;
while (m--)
{
scanf("%d%d%d",&opt,&u,&v);
if (opt==1) union_(u,v);
else if (find(u)==find(v)) printf("Y\n");else printf("N\n");
}
}
线段树(区间加/乘,求和模板)
难度:4
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define maxn 100050
using namespace std;
typedef long long ll;
int a[maxn],ql,qr,val,opt,n,m,p;
struct segment_tree
{
ll t[maxn*4],lz1[maxn*4],lz2[maxn*4];
inline void pushup(int x) {t[x]=t[x*2]+t[x*2+1];}
inline void pushdown(int x,int l,int r)
{
if (lz1[x]==1&&lz2[x]==0) return;
if (lz1[x]!=1)
{
lz1[x*2]=(lz1[x]*lz1[x*2])%p;
lz1[x*2+1]=(lz1[x]*lz1[x*2+1])%p;
lz2[x*2]=(lz1[x]*lz2[x*2])%p;
lz2[x*2+1]=(lz1[x]*lz2[x*2+1])%p;
t[x*2]=(t[x*2]*lz1[x])%p;
t[x*2+1]=(t[x*2+1]*lz1[x])%p;
lz1[x]=1;
}
int mid=(l+r)/2;
if (lz2[x]!=0)
{
lz2[x*2]=(lz2[x*2]+lz2[x])%p;
lz2[x*2+1]=(lz2[x*2+1]+lz2[x])%p;
t[x*2]=(t[x*2]+(mid-l+1)*lz2[x])%p;
t[x*2+1]=(t[x*2+1]+(r-mid)*lz2[x])%p;
lz2[x]=0;
}
}
inline void build(int x,int l,int r)
{
if (l==r) {t[x]=a[l],lz1[x]=1;return;}
int mid=(l+r)/2;
build(x*2,l,mid),build(x*2+1,mid+1,r),pushup(x),lz1[x]=1;
}
inline void upd(int x,int l,int r,int ql,int qr,int val,int k) //k=1:* k=2:+
{
if (l==ql&&r==qr)
{
if (k==1) lz1[x]=(lz1[x]*val)%p,lz2[x]=(lz2[x]*val)%p,t[x]=(t[x]*val)%p;
if (k==2) lz2[x]=lz2[x]+val,t[x]=(t[x]+val*(r-l+1))%p;
return;
}
pushdown(x,l,r);
int mid=(l+r)/2;
if (qr<=mid) upd(x*2,l,mid,ql,qr,val,k);
else if (ql>mid) upd(x*2+1,mid+1,r,ql,qr,val,k);
else upd(x*2,l,mid,ql,mid,val,k),upd(x*2+1,mid+1,r,mid+1,qr,val,k);
pushup(x);
}
inline ll query(int x,int l,int r,int ql,int qr)
{
if (l==ql&&r==qr) {return t[x]%p;}
pushdown(x,l,r),pushup(x);
int mid=(l+r)/2;
if (qr<=mid) return query(x*2,l,mid,ql,qr)%p;
else if (ql>mid) return query(x*2+1,mid+1,r,ql,qr)%p;
else return (query(x*2,l,mid,ql,mid)+query(x*2+1,mid+1,r,mid+1,qr))%p;
}
}s;
inline void rd(int &x)
{
x=0;
char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-48,ch=getchar();
}
int main()
{
rd(n),rd(m),rd(p);
for (int i=1;i<=n;i++) rd(a[i]);
s.build(1,1,n);
while (m--)
{
rd(opt);
if (opt==1) rd(ql),rd(qr),rd(val),s.upd(1,1,n,ql,qr,val,1);
if (opt==2) rd(ql),rd(qr),rd(val),s.upd(1,1,n,ql,qr,val,2);
if (opt==3) rd(ql),rd(qr),printf("%lld\n",s.query(1,1,n,ql,qr));
}
}
树状数组
单点加/区间求和:(l到r和为query®-query(l-1))
区间加/单点询问:(l到r加x:add(l,x),add(r+1,-x))
inline void add(int x,int y) {while (x<=n) t[x]+=y,x+=lowbit(x);}
inline int query(int x)
{
int ret=0;
while (x>=1) ret+=t[x],x-=lowbit(x);
return ret;
}
区间修改+查询:
inline void add(ll p,ll x){
for(int i=p;i<=n;i+=lowbit(i))
sum1[i]+=x,sum2[i]+=x*p;
}
inline void Add(ll l,ll r,ll x){add(l,x),add(r+1,-x);}
inline ll ask(ll p){
ll res=0;
for (int i=p;i;i-=lowbit(i)) res+=(p+1)*sum1[i]-sum2[i];
return res;
}
inline ll Ask(ll l, ll r){return ask(r)-ask(l-1);}
字符串
KMP算法
#include<bits/stdc++.h>
#define N 2000050
using namespace std;
char s[N],t[N];
int next[N],len1,len2,k;
int main()
{
scanf("%s",s+1),scanf("%s",t+1),k=0,len1=strlen(s+1),len2=strlen(t+1),next[1]=0;
for (int i=2;i<=len2;i++)
{
while (k>0&&t[i]!=t[k+1]) k=next[k];
if (t[i]==t[k+1]) k++;
next[i]=k;
}
k=0;
for (int i=1;i<=len1;i++)
{
while (k>0&&s[i]!=t[k+1]) k=next[k];
if (s[i]==t[k+1]) k++;
if (k==len2) k=next[k],printf("%d\n",i-len2+1);
}
for (int i=1;i<=len2;i++) printf("%d ",next[i]);
}