模板
快读
char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf; #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++) inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) x=x*10+(ch^48),ch=getchar(); return x*f; }
堆
操作1: 1 x 表示将x插入到堆中
操作2: 2 输出该小根堆内的最小数
操作3: 3 删除该小根堆内的最小数
#include<iostream> #include<algorithm> #include<queue> #include<cstdio> using namespace std; priority_queue<int,vector<int>,greater<int> > q; int n,x; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int main() { n=read(); for(int i=1; i<=n; i++) { x=read(); if(x==1) { x=read(); q.push(x); } else if(x==2) printf("%d\n",q.top()); else q.pop(); } }
最长公共子序列
#include<iostream> #include<cstdio> using namespace std; int a[100001],b[100001],map[100001],f[100001]; int main() { int n; cin>>n; for(int i=1;i<=n;i++){scanf("%d",&a[i]);map[a[i]]=i;} for(int i=1;i<=n;i++){scanf("%d",&b[i]);f[i]=0x7fffffff;} int len=0; f[0]=0; for(int i=1;i<=n;i++) { int l=0,r=len,mid; if(map[b[i]]>f[len])f[++len]=map[b[i]]; else { while(l<r) { mid=(l+r)/2; if(f[mid]>map[b[i]])r=mid; else l=mid+1; } f[l]=min(map[b[i]],f[l]); } } cout<<len; return 0 }
前向星
struct node{ int to, nxt, l; }e[maxn << 1]; int head[maxn], tot = 0; void addedge(int u, int v, int l){ e[++tot].to = v, e[tot].nxt = head[u], e[tot].l = l; head[u] = tot; }
割点
void tarjan(int u,int fa){ dfn[u]=low[u]=++now; int child=0; for(int i=head[u];i!=0;i=edge[i].nxt){ int Next=edge[i].to; if(dfn[Next]==0){ tarjan(Next,fa); low[u]=min(low[u],low[Next]); if (low[Next]>=dfn[u]&&u!=fa) cut[u]=1; if(u==fa) child++; } low[u]=min(low[u],dfn[Next]); } if(child>=2 && u==fa) cut[u]=1; } int work(){ for(int i=1;i<=m;i++) if(dfn[i]==0) tarjan(i,i); }
拓扑
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int indegree[100]; int n,m; bool map[100][100]; int a[100]; int topu() { queue<int> q; int cnt = 1; while(!q.empty())//清空队列 q.pop(); for(int i = 1; i <= n ; i++) if(indegree[i] == 0) q.push(i);//将 没有依赖顶点的节点入队 int u; while(!q.empty()) // { u = q.front(); a[cnt++] = u;//将上边选出的没有依赖顶点的节点加入到排序结果中 q.pop();//删除队顶元素 for(int i = 1; i <= n ; i++) { if(map[u][i]) { indegree[i] --;//删去以u为顶点的边 if(indegree[i] == 0) //如果节点i的所有依赖顶点连接边都已经删去 q.push(i); //即变为无依赖顶点的节点 将其入队 } } if(cnt == n+1)//如果排序完成输出结果 { for(int i = 1 ; i <= n ; i++) printf(" %d",a[i]); } } } int main() { int u,v; while(~scanf("%d%d",&n,&m)) { memset(indegree,0,sizeof(indegree)); memset(map,0,sizeof(map)); for(int i = 0 ; i < m ; i++) { scanf("%d%d",&u,&v); if(!map[u][v])//考虑重边 { indegree[v]++;//连接v的边的条数 map[u][v] = 1;//标记u v已经连接 } } topu(); } return 0; }
强连通分量
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜 欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你 算出有多少头奶牛可以当明星。
首先,不难发现,如果这所有的牛都存在同一个强联通分量里。那么它们一定互相受欢迎。 那么,我们怎么来找明星呢。 很简单,找出度为00的强联通分量中的点。这样可以保证所有的人都喜欢它,但是它不喜欢任何人,所以说不存在还有人事明星。 此题还有一个特殊情况: 如果有两个点分别满足出度为零的条件,则没有明星,这样无法满足所有的牛喜欢他。 有了上边的解释,题目就不是那么难了,代码如下 #include<bits/stdc++.h> #define ri register int using namespace std; const int maxn=1e4+5; const int maxm=5e4+5; int to[maxm],nex[maxm],fir[maxn]; int col,num,dfn[maxn],low[maxn],de[maxn],si[maxn]; int tot=0,co[maxn],n,m; int top,st[maxn]; template<class T> inline void read(T &x) { x=0; register char c=getchar(); register bool f=0; while (!isdigit(c)) f ^=c=='-',c=getchar(); while (isdigit(c)) x=x*10+c-'0',c=getchar(); if(f)x=-x; } template <class T> inline void print(T x) { if(x<0)putchar('-'),x=-x; if(x>9)print(x/10); putchar('0'+x%10); } inline void ins(int x,int y) { to[++tot]=y; nex[tot]=fir[x]; fir[x]=tot; } void Tarjan(int u) { dfn[u]=low[u]=++num; st[++top]=u; for(int i=fir[u];i;i=nex[i]) { int v=to[i]; if(!dfn[v]) { Tarjan(v); low[u]=min(low[u],low[v]); } else if(!co[v])low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { co[u]=++col; ++si[col]; while(st[top]!=u) { ++si[col]; co[st[top]]=col; --top; } --top; } } int main() { int x,y; read(n);read(m); for(ri i=1;i<=m;i++) { read(x);read(y); ins(y,x); } for(ri i=1;i<=n;i++) if(!dfn[i])Tarjan(i); for(ri i=1;i<=n;i++) for(ri j=fir[i];j;j=nex[j]) if(co[i]!=co[to[j]])de[co[to[j]]]++; int ans=0,u=0; for(ri i=1;i<=col;i++)if(!de[i])ans=si[i],u++; if(u==1)print(ans); else print(0); return 0; }
缩点
void Tarjan(int x){ sta.push(x); ins[x]=1; dfn[x]=low[x]=++idx; for(int i=head[x];i;i=edge[i].nxt){ int upup=edge[i].to; if(!dfn[upup]){ Tarjan(upup); low[x]=min(low[x],low[upup]); } else if(ins[upup]){ low[x]=min(low[x],dfn[upup]); } } if(dfn[x]==low[x]){ tot++; while(sta.top()!=x){ color[sta.top()]=tot; sum[tot]+=val[sta.top()]; ins[sta.top()]=0; sta.pop(); } color[sta.top()]=tot; sum[tot]+=val[sta.top()]; ins[sta.top()]=0; sta.pop(); } } SPFA void SPFA(){ memset(dis,0x3f,sizeof(dis)); memset(times,0,sizeof(times)); memset(Find,false,sizeof(Find)); times[start]=1; dis[start]=0; Find[start]=true; qu1.push(start); while(!qu1.empty()){ int now=qu1.front(); for(int i=head[now];i;i=edge[i].nxt){ int upup=edge[i].to; if(dis[now]+edge[i].w<dis[upup]){ dis[upup]=dis[now]+edge[i].w; if(!Find[upup]){ qu1.push(upup); Find[upup]=true; times[upup]++; if(times[upup]>n) return; } } } qu1.pop(); Find[now]=false; } }
kruskal
#include<cstdio> #include<algorithm> using namespace std; const int maxn = 10000; int u[maxn], v[maxn], w[maxn]; int n, m; int p[maxn], r[maxn]; bool cmp(int i, int j){return w[i] < w[j];} int find(int x){return p[x] == x? x: p[x] = find(p[x]);} int Kruskal(){ for(int i = 1; i <= m; ++i) r[i] = i; for(int i = 1; i <= n; ++i) p[i] = i; sort(r+1, r+m+1, cmp); int k = 0, ans = 0; for(int i = 1 ; i <= m; ++i) { int e = r[i]; int x = find(u[e]), y = find(v[e]); if(x!=y){ ans += w[e]; ++k; p[x] = y;} if ( k == n-1 )break; } int root = find(1); for(int i =1 ;i <=n; ++i) if(find(i)!=root) return -1; return ans; } int main(){ scanf("%d%d", &n, &m); for(int i = 1; i <= m; ++i) scanf("%d%d%d", u+i, v+i, w+i); printf("%d\n", Kruskal()); return 0; } /* 5 7 1 2 5 1 3 1 1 4 2 1 5 4 2 4 1 3 4 5 3 5 2 (6) 5 7 1 5 6 2 5 7 2 4 7 2 3 9 1 4 5 1 2 4 3 4 2 (17)
dijkstra堆优化
int n,m,start,dis[maxn],head[maxn],cnt; bool vis[maxn]; struct node{ int nxt,weight,to; }edge[maxm]; struct qnode{ int dis,id; bool operator <(qnode x)const{ return dis>x.dis; } }; priority_queue<qnode> q; void addedge(int x,int y,int z){ edge[++cnt].to=y; edge[cnt].weight=z; edge[cnt].nxt=head[x]; head[x]=cnt; } void Dijkstra(){ while(!q.empty()){ start=q.top().id; q.pop(); if(vis[start]) continue; vis[start]=true; for(int i=head[start];i;i=edge[i].nxt){ int upup=edge[i].to; if(dis[upup]>dis[start]+edge[i].weight){ dis[upup]=min(dis[upup],edge[i].weight+dis[start]); if(!vis[upup]) q.push((qnode){dis[upup],upup}); } } } void Init(){ scanf("%d%d%d",&n,&m,&start); for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); } memset(dis,0x3f,sizeof(dis)); dis[start]=0; memset(vis,false,sizeof(vis)); while(!q.empty()) q.pop(); q.push((qnode){0,start}); } void print(){ for(int i=1;i<=n;i++) printf("%d ",dis[i]); puts(""); } }
欧拉筛
bool isPrime[1000001]; //isPrime[i] == 1表示:i是素数 int Prime[1000001], cnt = 0; //Prime存质数 void GetPrime(int n)//筛到n { memset(isPrime, 1, sizeof(isPrime)); //以“每个数都是素数”为初始状态,逐个删去 isPrime[1] = 0;//1不是素数 for(int i = 2; i <= n; i++) { if(isPrime[i])//没筛掉 Prime[++cnt] = i; //i成为下一个素数 for(int j = 1; j <= cnt && i*Prime[j] <= n/*不超上限*/; j++) { //从Prime[1],即最小质数2开始,逐个枚举已知的质数,并期望Prime[j]是(i*Prime[j])的最小质因数 //当然,i肯定比Prime[j]大,因为Prime[j]是在i之前得出的 isPrime[ i*Prime[j] ] = 0; if(i % Prime[j] == 0)//i中也含有Prime[j]这个因子 break; //重要步骤。见原理 } } }
快速幂
#include<bits/stdc++.h> using namespace std; long long b,a,p,k,ans=1,c; int main() { scanf("%d%d%d",&b,&p,&k); a=b;c=p; while(p>0)//快速幂 { if(p%2!=0) ans=ans*b%k;//如果p为单数,乘到ans里面去,然后取模 b=b*b%k;//每次运算都取模 p=p>>1; //用位运算除2,可能会快一点 } printf("%d^%d mod %d=%d",a,c,k,ans);//输出 return 0; }
同余方程
求关于x的同余方程 ax≡1(modb) 的最小正整数解。
#include <iostream> #include <cstdio> using namespace std; int a,b,x,y,k; void exgcd(int a,int b) { if(b==0) { x=1; y=0; return; } exgcd(b,a%b); k=x; x=y; y=k-a/b*y; return; } int main() { ios::sync_with_stdio(false); cin>>a>>b; exgcd(a,b); cout<<(x+b)%b; }
并查集
接下来M行,每行包含三个整数Zi、Xi、Yi
当Zi=1时,将Xi与Yi所在的集合合并
当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N
#include<bits/stdc++.h> using namespace std; int n,m,z[666666],x[666666],y[666666]; int f[666666]; int find(int x)//找爸爸 { if(f[x]==x) { return x; } else { f[x]=find(f[x]); } return f[x]; } void work1(int x,int y)//合并 { f[find(y)]=find(x); } void work2(int x,int y)//查询 { if(find(x)==find(y)) { cout<<"Y"<<endl; } else { cout<<"N"<<endl; } } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); ios::sync_with_stdio(false);//关闭同步使cin,cout变快 cin>>n>>m; for(int i=1;i<=m;i++) { cin>>z[i]>>x[i]>>y[i]; f[i]=i; } for(int i=1;i<=m;i++) { if(z[i]==1) { work1(x[i],y[i]); } else { work2(x[i],y[i]); } } return 0;//完结撒花 }
KMP
如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。
为了减少骗分的情况,接下来还要输出子串的前缀数组next。
#include<cstdio> #include<iostream> #include<algorithm> #include<string> #include<cstring> #include<cmath> using namespace std; char a1[2000000],a2[2000000]; int kmp[2000000]; int main() { scanf("%s%s",a1,a2); kmp[0]=kmp[1]=0;//前一位,两位失配了,都只可能将第一位作为新的开头 int len1=strlen(a1),len2=strlen(a2); int k; k=0; for(int i=1;i<len2;i++)//自己匹配自己 { while(k&&a2[i]!=a2[k])k=kmp[k];//找到最长的前后缀重叠长度 kmp[i+1]=a2[i]==a2[k]?++k:0;//不相等的情况,即无前缀能与后缀重叠,直接赋值位0(注意是给下一位,因为匹配的是下一位适失配的情况) } k=0; for(int i=0;i<len1;i++) { while(k&&a1[i]!=a2[k])k=kmp[k];//如果不匹配,则将利用kmp数组往回跳 k+=a1[i]==a2[k]?1:0;//如果相等了,则匹配下一位 if(k==len2)printf("%d\n",i-len2+2);//如果已经全部匹配完毕,则输出初始位置 } for(int i=1;i<=len2;i++)printf("%d ",kmp[i]);//输出f数组 return 0; }
LCA
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。
接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。
#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int maxn=500000+2; int n,m,s; int k=0; int head[maxn],d[maxn],p[maxn][21];//head数组就是链接表标配了吧?d存的是深度(deep),p[i][j]存的[i]向上走2的j次方那么长的路径 struct node{ int v,next; }e[maxn*2];//存树 void add(int u,int v) { e[k].v=v; e[k].next=head[u]; head[u]=k++; } //加边函数 void dfs(int u,int fa) { d[u]=d[fa]+1; p[u][0]=fa; for(int i=1;(1<<i)<=d[u];i++) p[u][i]=p[p[u][i-1]][i-1]; for(int i=head[u];i!=-1;i=e[i].next) { int v=e[i].v; if(v!=fa) dfs(v,u); } } //首先进行的预处理,将所有点的deep和p的初始值dfs出来 int lca(int a,int b) //非常标准的lca查找 { if(d[a]>d[b]) swap(a,b); //保证a是在b结点上方,即a的深度小于b的深度 for(int i=20;i>=0;i--) if(d[a]<=d[b]-(1<<i)) b=p[b][i]; //先把b移到和a同一个深度 if(a==b) return a; //特判,如果b上来和就和a一样了,那就可以直接返回答案了 for(int i=20;i>=0;i--) { if(p[a][i]==p[b][i]) continue; else a=p[a][i],b=p[b][i]; //A和B一起上移 } return p[a][0]; 找出最后a值的数字 } int main() { memset(head,-1,sizeof(head)); int a,b; scanf("%d%d%d",&n,&m,&s); for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); add(a,b); add(b,a); //无向图,要加两次 } dfs(s,0); for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); printf("%d\n",lca(a,b)); } return 0; }
线段树(区间加,区间和)
#include<iostream> #include<cstdio> #define MAXN 1000005 #define ll long long using namespace std; ll a[MAXN],ans[MAXN<<2],tag[MAXN<<2]; ll ls(ll x) { return x<<1; } ll rs(ll x) { return x<<1|1; } void push_up(ll p) { ans[p]=ans[ls(p)]+ans[rs(p)]; } void build(ll p,ll l,ll r) { tag[p]=0; if(l==r) { ans[p]=a[l]; return ; } ll mid=(l+r)>>1; build(ls(p),l,mid); build(rs(p),mid+1,r); push_up(p); } void f(ll p,ll l,ll r,ll k) { tag[p]=tag[p]+k; ans[p]=ans[p]+k*(r-l+1); } void push_down(ll p,ll l,ll r) { ll mid=(l+r)>>1; f(ls(p),l,mid,tag[p]); f(rs(p),mid+1,r,tag[p]); tag[p]=0; } void update(ll nl,ll nr,ll l,ll r,ll p,ll k) { if(nl<=l&&r<=nr) { ans[p]+=k*(r-l+1); tag[p]+=k; return ; } push_down(p,l,r); ll mid=(l+r)>>1; if(nl<=mid)update(nl,nr,l,mid,ls(p),k); if(nr>mid) update(nl,nr,mid+1,r,rs(p),k); push_up(p); } ll query(ll q_x,ll q_y,ll l,ll r,ll p) { ll res=0; if(q_x<=l&&r<=q_y)return ans[p]; ll mid=(l+r)>>1; push_down(p,l,r); if(q_x<=mid)res+=query(q_x,q_y,l,mid,ls(p)); if(q_y>mid) res+=query(q_x,q_y,mid+1,r,rs(p)); return res; } int main() { ll a1,b,c,d,e,f,n,m; scanf("%lld%lld",&n,&m); for(ll i=1; i<=n; i++) scanf("%lld",&a[i]); build(1,1,n); while(m--) { scanf("%lld",&a1); switch(a1) { case 1: { scanf("%lld%lld%lld",&b,&c,&d); update(b,c,1,n,1,d); break; } case 2: { scanf("%lld%lld",&e,&f); printf("%lld\n",query(e,f,1,n,1)); break; } } } return 0; }
网络流(EK,Dinic,ISAP)
#include <cstdio> #include <memory.h> #include <queue> #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define MAXN 10000 #define MAXM 100000 #define INF (1<<30) namespace G{ /* 本例中使用前向星存图 注意它与普通前向星的区别: 普通前向星编号从1开始,而这里从0开始 这样可以确保第i条边的反向弧就是第i^1条边 */ int n,m,S,T; struct Edge{ int from,to,cap,nxt; }e[MAXM*2+10]; int head[MAXN+10],cur[MAXN+10],cnt; inline void Init(){ //初始化,准备建图 memset(head,-1,sizeof(head)); cnt=-1; } inline void AddEdge(int u,int v,int w){ //添加一条边及其反向弧 e[++cnt]=(Edge){u,v,w,head[u]}; //加入这条边 head[u]=cnt; e[++cnt]=(Edge){v,u,0,head[v]}; //加入它的反向弧 head[v]=cnt; } //以下为Dinic int dep[MAXN+10]; //记录每个点的编号 bool Dinic_BFS(){ std::queue<int> q; memset(dep,0,sizeof(dep)); dep[S]=1; q.push(S); while(!q.empty()){ int x=q.front(); q.pop(); for(int i=head[x];~i;i=e[i].nxt) if(e[i].cap>0 && dep[e[i].to]==0){ dep[e[i].to]=dep[x]+1; q.push(e[i].to); } } return dep[T]; } int Dinic_DFS(int u,int now){ if(u==T) return now; int ret=0; for(int &i=cur[u];~i;i=e[i].nxt) //当前弧优化 if(dep[e[i].to]==dep[u]+1 && e[i].cap){ int di=Dinic_DFS(e[i].to,min(e[i].cap,now-ret)); //向下搜索 if(di){ //增广 e[i].cap-=di; e[i^1].cap+=di; ret+=di; if(ret==now) break; } } return ret; } inline int Dinic(){ int ret=0; while(Dinic_BFS()){ //BFS分层 memcpy(cur,head,sizeof(head)); //当前弧优化 ret+=Dinic_DFS(S,INF); //DFS找增广路 } return ret; } //以下为EK bool vis[MAXN+10]; //记录每个点是否经过 int pre[MAXN+10]; //记录增广路 int EK_BFS(){ memset(pre,-1,sizeof(pre)); memset(vis,false,sizeof(vis)); std::queue<int> q; q.push(S); vis[S]=true; while(!q.empty()){ int x=q.front(); q.pop(); for(int i=head[x];~i;i=e[i].nxt) if(e[i].cap>0 && !vis[e[i].to]){ pre[e[i].to]=i; vis[e[i].to]=true; if(e[i].to==T) return true; q.push(e[i].to); } } return false; } inline int EK(){ int ret=0; while(EK_BFS()){ //BFS找增广路 int di=INF; for(int i=pre[T];~i;i=pre[e[i].from]) //找到这条路上容量最小的边 di=min(di,e[i].cap); for(int i=pre[T];~i;i=pre[e[i].from]){ //增广 e[i].cap-=di; e[i^1].cap+=di; } ret+=di; } return ret; } //以下为ISAP int gap[MAXN+10]; //GAP优化:当某一层没有任何点时停止算法 void ISAP_BFS(){ //BFS初始化 memset(dep,-1,sizeof(dep)); memset(gap,0,sizeof(gap)); dep[T]=0; gap[1]=1; std::queue<int> q; q.push(T); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];~i;i=e[i].nxt){ if(dep[e[i].to]!=-1) continue; q.push(e[i].to); dep[e[i].to]=dep[u]+1; gap[dep[e[i].to]]++; //更新GAP数组 } } return; } int ISAP_DFS(int u,int flow){ //DFS增广,原理类似Dinic,不解释 if(u==T) return flow; int ret=0; for(int &i=cur[u];~i;i=e[i].nxt){ if(e[i].cap && dep[e[i].to]+1==dep[u]){ int di=ISAP_DFS(e[i].to,min(e[i].cap,flow-ret)); if(di){ e[i].cap-=di; e[i^1].cap+=di; ret+=di; } if(ret==flow) return ret; } } gap[dep[u]]--; if(gap[dep[u]]==0) //GAP优化 dep[S]=n+1; dep[u]++; gap[dep[u]]++; return ret; } int ISAP(){ ISAP_BFS(); int ret=0; while(dep[S]<=n){ memcpy(cur,head,sizeof(head)); //当前弧优化 ret+=ISAP_DFS(S,INF); } return ret; } } int main(){ //主程序,不解释 scanf("%d%d%d%d",&G::n,&G::m,&G::S,&G::T); G::Init(); for(int i=1;i<=G::m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); G::AddEdge(u,v,w); } //printf("%d\n",G::Dinic()); // printf("%d\n",G::EK()); printf("%d\n",G::ISAP()); return 0; }
网络流(ISAP)优版
#include<cstdio> #include<algorithm> #include<queue> #include<cstring> #define LL long long #define MAXN 100000+5 using namespace std; inline int read() { char ch=getchar();int x=0,f=1; while (ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();} while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } struct Node { int v,next,w; }; Node node[(MAXN)<<1]; int dis[10001],gap[10001]; int p[10001],pp[10001]; int cnt=-1; int s,t,n,m; bool used[10001]; queue<int> q; void addedge(int u,int v,int w) { node[++cnt].v=v; node[cnt].next=p[u]; node[cnt].w=w; p[u]=cnt; } void bfs(int o) { q.push(o); dis[o]=0; used[o]=1; while(!q.empty()) { int head=q.front(); gap[dis[head]]++; for(int i=p[head];~i;i=node[i].next) if(node[i^1].w&&!used[node[i].v]) { dis[node[i].v]=dis[head]+1; used[node[i].v]=1; q.push(node[i].v); } q.pop(); } } int flow(int o,int flows) { if(o==t) return flows; int sum=0; for(int i=p[o];~i;i=node[i].next) if(node[i].w&&dis[node[i].v]==dis[o]-1) { int f=flow(node[i].v,min(flows-sum,node[i].w)); node[i].w-=f;node[i^1].w+=f; sum+=f;p[o]=i; if (sum==flows||dis[s]==n) return sum; } if (!--gap[dis[o]++]) dis[s]=n; ++gap[dis[o]];p[o]=pp[o]; return sum; } int main() { n=read(),m=read(),s=read(),t=read(); memset(p,-1,sizeof(p)); for(int i=1;i<=m;i++) { int u=read(),v=read(),w=read(); addedge(u,v,w); addedge(v,u,0); } memcpy(pp,p,sizeof(p)); bfs(t); long long ans=0; while(dis[s]<n) ans+=(LL)(flow(s,0x7fffffff)); printf("%lld\n",ans); return 0; }
FFT(高精乘)
#include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <complex> #define space putchar(' ') #define enter putchar('\n') using namespace std; typedef long long ll; template <class T> void read(T &x){ char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x){ if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int N = 1000005; const double PI = acos(-1); typedef complex <double> cp; char sa[N], sb[N]; int n = 1, lena, lenb, res[N]; cp a[N], b[N], omg[N], inv[N]; void init(){ for(int i = 0; i < n; i++){ omg[i] = cp(cos(2 * PI * i / n), sin(2 * PI * i / n)); inv[i] = conj(omg[i]); } } void fft(cp *a, cp *omg){ int lim = 0; while((1 << lim) < n) lim++; for(int i = 0; i < n; i++){ int t = 0; for(int j = 0; j < lim; j++) if((i >> j) & 1) t |= (1 << (lim - j - 1)); if(i < t) swap(a[i], a[t]); // i < t 的限制使得每对点只被交换一次(否则交换两次相当于没交换) } for(int l = 2; l <= n; l *= 2){ int m = l / 2; for(cp *p = a; p != a + n; p += l) for(int i = 0; i < m; i++){ cp t = omg[n / l * i] * p[i + m]; p[i + m] = p[i] - t; p[i] += t; } } } int main(){ scanf("%s%s", sa, sb); lena = strlen(sa), lenb = strlen(sb); while(n < lena + lenb) n *= 2; for(int i = 0; i < lena; i++) a[i].real(sa[lena - 1 - i] - '0'); for(int i = 0; i < lenb; i++) b[i].real(sb[lenb - 1 - i] - '0'); init(); fft(a, omg); fft(b, omg); for(int i = 0; i < n; i++) a[i] *= b[i]; fft(a, inv); for(int i = 0; i < n; i++){ res[i] += floor(a[i].real() / n + 0.5); res[i + 1] += res[i] / 10; res[i] %= 10; } for(int i = res[lena + lenb - 1] ? lena + lenb - 1: lena + lenb - 2; i >= 0; i--) putchar('0' + res[i]); enter; return 0; }
FFT(多项式乘法)
#include <cmath> #include <cstdio> #include <iostream> #define il inline using namespace std ; int N, M, K ; const int MAXN = 3000100 ; const double Pi = acos(-1.0) ; int i, j, k, l, Lim = 1, L, R[MAXN] ; struct node{ double x, y ; node (double xx = 0, double yy = 0){ x = xx, y = yy ; } }A[MAXN], B[MAXN] ; node operator * (node J, node Q){ return node(J.x * Q.x - J.y * Q.y , J.x * Q.y + J.y * Q.x); } node operator + (node J, node Q){ return node(J.x + Q.x , J.y + Q.y); } node operator - (node J, node Q){ return node(J.x - Q.x , J.y - Q.y ); } il int qr(){ int k = 0, f = 1 ; char c = getchar() ; while(!isdigit(c)){if(c == '-') f = -1 ;c = getchar() ;} while(isdigit(c)) k = (k << 1) + (k << 3) + c - 48 ,c = getchar() ; return k * f ; } void FFT(node *J, int flag){ for(i = 0; i < Lim; i ++) if(i < R[i]) swap(J[i], J[R[i]]) ; for(j = 1; j < Lim; j <<= 1){ node T(cos(Pi / j), flag * sin(Pi / j)) ; for(k = 0; k < Lim; k += (j << 1) ){ node t(1, 0) ; for(l = 0 ; l < j; l ++, t = t * T){ node Nx = J[k + l], Ny = t * J[k + j + l] ; J[k + l] = Nx + Ny ; J[k + j + l] = Nx - Ny ; } } } } int main(){ N = qr(), M = qr() ; for(i = 0; i <= N; i ++) A[i].x = qr() ; for(i = 0; i <= M; i ++) B[i].x = qr() ; while(Lim <= N + M) Lim <<= 1, L ++ ; for(i = 0; i < Lim; i ++ ) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1)) ; FFT(A, 1), FFT(B, 1) ; for(i = 0; i <= Lim; i ++) A[i] = A[i] * B[i] ; FFT(A, -1) ; for(i = 0; i <= N + M; i ++) printf("%d ", (int)(A[i].x / Lim + 0.5)) ; puts(""); return 0 ; }
char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();return x*f;}