1. 103E

大意: 给定$n$个集合, 满足对于任意的$k$, 任意$k$个集合的并集都不少于$k$. 要求选出$k$个集合$(k> 0)$, 使得并恰好等于$k$, 输出最少花费.

Hall定理: 二分图的$X$部到$Y$部有完美匹配等价于$X$中任意$k$个点与$Y$中至少$k$个点相邻.

所有集合为$X$部, 每个数为$Y$部, 集合向所含数连边, 那么一定存在完美匹配. 假设求出一组匹配, 数字$i$对应集合$C_i$, 那么最终若选取集合$A_i$, 则$A_i$中所有数字$x$对应的集合$C_x$一定也要选, 把权值取负就转化为最大权闭合子图模型. 对于最大权闭合子图问题, 源点连所有正权点, 容量为该点权值, 所有负权点连汇点, 容量为该点权值的绝对值, 其余边与原图一样, 容量为无穷, 求出源点到汇点的最小割, 那么答案为正权和-最小割, 与源点间的割的含义为不选择该点, 与汇点间的割的含义为选择该点.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. #define pb push_back
  6. using namespace std;
  7.  
  8. const int N = 1e6+, INF = 0x3f3f3f3f;
  9. int n, S, T, clk, f[N], vis[N];
  10. vector<int> g[N];
  11. int dfs(int x) {
  12. for (int y:g[x]) if (vis[y]!=clk) {
  13. vis[y] = clk;
  14. if (!f[y]||dfs(f[y])) return f[y]=x;
  15. }
  16. return ;
  17. }
  18. struct edge {
  19. int v,w,next;
  20. } e[N];
  21. int head[N], dep[N], cur[N], cnt=;
  22. queue<int> Q;
  23. void add(int u, int v, int w) {
  24. e[++cnt] = {v,w,head[u]};
  25. head[u] = cnt;
  26. e[++cnt] = {u,,head[v]};
  27. head[v] = cnt;
  28. }
  29. int bfs() {
  30. REP(i,,T) dep[i]=INF,vis[i]=,cur[i]=head[i];
  31. dep[S]=,Q.push(S);
  32. while (Q.size()) {
  33. int u = Q.front(); Q.pop();
  34. for (int i=head[u]; i; i=e[i].next) {
  35. if (dep[e[i].v]>dep[u]+&&e[i].w) {
  36. dep[e[i].v]=dep[u]+;
  37. Q.push(e[i].v);
  38. }
  39. }
  40. }
  41. return dep[T]!=INF;
  42. }
  43. int dfs(int x, int w) {
  44. if (x==T) return w;
  45. int used = ;
  46. for (int i=cur[x]; i; i=e[i].next) {
  47. cur[x] = i;
  48. if (dep[e[i].v]==dep[x]+&&e[i].w) {
  49. int flow = dfs(e[i].v,min(w-used,e[i].w));
  50. if (flow) {
  51. used += flow;
  52. e[i].w -= flow;
  53. e[i^].w += flow;
  54. if (used==w) break;
  55. }
  56. }
  57. }
  58. return used;
  59. }
  60. int dinic() {
  61. int ans = ;
  62. while (bfs()) ans+=dfs(S,INF);
  63. return ans;
  64. }
  65.  
  66. int main() {
  67. scanf("%d", &n), S = n+, T = S+;
  68. REP(i,,n) {
  69. int k, t;
  70. scanf("%d", &k);
  71. while (k--) {
  72. scanf("%d", &t);
  73. g[i].pb(t+n);
  74. g[t+n].pb(i);
  75. }
  76. }
  77. REP(i,,n) ++clk, dfs(i);
  78. int sum = ;
  79. REP(i,,n) {
  80. int t;
  81. scanf("%d", &t);
  82. t = -t;
  83. if (t>=) add(S,i,t),sum+=t;
  84. else add(i,T,-t);
  85. }
  86. REP(i,,n) for (int j:g[i]) add(i,f[j],INF);
  87. printf("%d\n", dinic()-sum);
  88. }

2. 164C

大意: $k$台机器, $n$个任务, 任务$i$开始时间$s_i$, 持续时间$t_i$, 获利$c_i$, 每台机器可以处理任何任务, 没处理完不能切换, 求完成哪些任务收益最大.

最大$k$重区间集问题, 时间离散化, 每个时间向下一个时间连容量$k$, 花费$0$, 任务$i$起点向终点连容量$1$, 花费$c_i$, 求出最大费用最大流即可.

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstdio>
  4. #include <queue>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. using namespace std;
  7.  
  8. const int N = 5e4+,S=N-,T=N-,INF=0x3f3f3f3f;
  9. int n,m,cost,flow,b[N];
  10. struct edge {
  11. int to,next,w,v;
  12. edge(int to=,int next=,int w=,int v=):to(to),next(next),w(w),v(v){}
  13. } e[N];
  14. int head[N],dep[N],vis[N],cnt=;
  15. queue<int> Q;
  16.  
  17. int spfa() {
  18. REP(i,,*b) dep[i]=-INF,vis[i]=;
  19. dep[T]=-INF;
  20. dep[S]=,Q.push(S);
  21. while (Q.size()) {
  22. int u = Q.front(); Q.pop();
  23. vis[u] = ;
  24. for (int i=head[u]; i; i=e[i].next) {
  25. if (e[i].w&&dep[e[i].to]<dep[u]+e[i].v) {
  26. dep[e[i].to]=dep[u]+e[i].v;
  27. if (!vis[e[i].to]) {
  28. vis[e[i].to]=;
  29. Q.push(e[i].to);
  30. }
  31. }
  32. }
  33. }
  34. return dep[T]!=-INF;
  35. }
  36. int dfs(int x, int w) {
  37. if (x==T) {
  38. cost = cost+w*dep[T];
  39. flow += w;
  40. return w;
  41. }
  42. vis[x] = ;
  43. int used = ;
  44. for (int i=head[x]; i; i=e[i].next) {
  45. if (!vis[e[i].to]&&dep[e[i].to]==dep[x]+e[i].v&&e[i].w) {
  46. int f = dfs(e[i].to,min(w-used,e[i].w));
  47. if (f) {
  48. used += f;
  49. e[i].w -= f;
  50. e[i^].w += f;
  51. if(used==w) break;
  52. }
  53. }
  54. }
  55. return used;
  56. }
  57. void dinic(){
  58. while(spfa()) dfs(S,INF);
  59. }
  60. void add(int x,int y,int k,int v) {
  61. e[++cnt] = edge(y,head[x],k,v);
  62. head[x] = cnt;
  63. e[++cnt] = edge(x,head[y],,-v);
  64. head[y] = cnt;
  65. }
  66.  
  67. int k,L[N],R[N],c[N],no[N];
  68. int main() {
  69. scanf("%d%d", &n, &k);
  70. REP(i,,n) {
  71. int s,t;
  72. scanf("%d%d%d",&s,&t,c+i);
  73. b[++*b]=L[i]=s;
  74. b[++*b]=R[i]=s+t;
  75. }
  76. sort(b+,b++*b),*b=unique(b+,b++*b)-b-;
  77. REP(i,,n) {
  78. L[i]=lower_bound(b+,b++*b,L[i])-b;
  79. R[i]=lower_bound(b+,b++*b,R[i])-b;
  80. }
  81. add(S,,k,),add(*b,T,k,);
  82. REP(i,,*b) add(i-,i,k,);
  83. REP(i,,n) no[i]=cnt+,add(L[i],R[i],,c[i]);
  84. dinic();
  85. REP(i,,n) printf("%d ", !e[no[i]].w);
  86. puts("");
  87. }

3. 237E

大意: 给定字符串$t$, 给定$n$个子串, 第$i$个子串$s_i$最多可以选出$a_i$个字符, 每个字符花费为$i$, 求组成字符串$t$的最少花费.

裸的费用流, 源点向子串$i$连容量$a_i$, 费用$0$, $i$向每个字符$x$连容量$cnt_s[x]$, 费用$i$, 最后每个字符$x$向汇点连容量$cnt_t[x]$, 费用0. 求最小费用即可.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. using namespace std;
  6.  
  7. const int N = 5e4+,S=N-,T=N-,INF=0x3f3f3f3f;
  8. int n,m,cost,flow,b[N];
  9. struct edge {
  10. int to,next,w,v;
  11. edge(int to=,int next=,int w=,int v=):to(to),next(next),w(w),v(v){}
  12. } e[N];
  13. int head[N],dep[N],vis[N],cnt=;
  14. queue<int> Q;
  15.  
  16. int spfa() {
  17. REP(i,,n+) dep[i]=INF,vis[i]=;
  18. dep[T]=INF;
  19. dep[S]=,Q.push(S);
  20. while (Q.size()) {
  21. int u = Q.front(); Q.pop();
  22. vis[u] = ;
  23. for (int i=head[u]; i; i=e[i].next) {
  24. if (e[i].w&&dep[e[i].to]>dep[u]+e[i].v) {
  25. dep[e[i].to]=dep[u]+e[i].v;
  26. if (!vis[e[i].to]) {
  27. vis[e[i].to]=;
  28. Q.push(e[i].to);
  29. }
  30. }
  31. }
  32. }
  33. return dep[T]!=INF;
  34. }
  35. int dfs(int x, int w) {
  36. if (x==T) {
  37. cost = cost+w*dep[T];
  38. flow += w;
  39. return w;
  40. }
  41. vis[x] = ;
  42. int used = ;
  43. for (int i=head[x]; i; i=e[i].next) {
  44. if (!vis[e[i].to]&&dep[e[i].to]==dep[x]+e[i].v&&e[i].w) {
  45. int f = dfs(e[i].to,min(w-used,e[i].w));
  46. if (f) {
  47. used += f;
  48. e[i].w -= f;
  49. e[i^].w += f;
  50. if(used==w) break;
  51. }
  52. }
  53. }
  54. return used;
  55. }
  56. void dinic(){
  57. while(spfa()) dfs(S,INF);
  58. }
  59. void add(int x,int y,int k,int v) {
  60. e[++cnt] = edge(y,head[x],k,v);
  61. head[x] = cnt;
  62. e[++cnt] = edge(x,head[y],,-v);
  63. head[y] = cnt;
  64. }
  65.  
  66. int f[N];
  67. char s[N];
  68.  
  69. int main() {
  70. scanf("%s%d", s+, &n);
  71. m = strlen(s+);
  72. REP(i,,m) ++f[s[i]];
  73. int sum = ;
  74. REP(i,'a','z') if (f[i]) {
  75. add(n+i-'a'+,T,f[i],),sum+=f[i],f[i]=;
  76. }
  77. REP(i,,n) {
  78. int x;
  79. scanf("%s%d", s+, &x);
  80. m = strlen(s+);
  81. REP(i,,m) ++f[s[i]];
  82. add(S,i,x,);
  83. REP(j,'a','z') if (f[j]) add(i,n+j-'a'+,f[j],i);
  84. REP(i,'a','z') f[i]=;
  85. }
  86. dinic();
  87. if (flow!=sum) return puts("-1"),;
  88. printf("%d\n", cost);
  89. }

4. 269C

大意:给定无向图, 求将边定向, 使它成为一个$1$到$n$的流.

拓扑排序即可.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. #define pb push_back
  6. using namespace std;
  7.  
  8. const int N = 1e6+;
  9. int n,m,deg[N],ans[N],vis[N];
  10. struct _ {int to,w,id;};
  11. vector<_> g[N];
  12.  
  13. int main() {
  14. scanf("%d%d", &n, &m);
  15. REP(i,,m) {
  16. int u,v,w;
  17. scanf("%d%d%d",&u,&v,&w);
  18. g[u].pb({v,w,i});
  19. g[v].pb({u,w,-i});
  20. deg[u]+=w,deg[v]+=w;
  21. }
  22. queue<int> q;
  23. q.push(),vis[n]=;
  24. memset(ans,-,sizeof ans);
  25. while (q.size()) {
  26. int x = q.front(); q.pop();
  27. vis[x] = ;
  28. for (_ e:g[x]) {
  29. if (e.id<) {
  30. if (ans[-e.id]==-) ans[-e.id]=;
  31. }
  32. else if (ans[e.id]==-) ans[e.id]=;
  33. if (!vis[e.to]) {
  34. if (!(deg[e.to]-=*e.w)) {
  35. q.push(e.to);
  36. }
  37. }
  38. }
  39. }
  40. REP(i,,m) printf("%d\n",ans[i]);
  41. }

5. 277E

大意: 给定$n$个平面点, $y$值大的可以向$y$值小的连有向边, 求一棵边权和最小的有根二叉树.

每个点入度1, 出度不超过2, 建图跑费用流即可.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #include <math.h>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. #define pb push_back
  7. using namespace std;
  8.  
  9. const int N = 1e5+, INF = 0x3f3f3f3f;
  10. int n, m, k;
  11. struct _ {int from,to,w;double f;};
  12. vector<_> E;
  13. vector<int> g[N];
  14. int a[N], pre[N], inq[N];
  15. double d[N];
  16. int mf;
  17. double mc;
  18. queue<int> q;
  19. void add(int x, int y, int c, double w) {
  20. g[x].pb(E.size());
  21. E.pb({x,y,c,w});
  22. g[y].pb(E.size());
  23. E.pb({y,x,,-w});
  24. }
  25. void mfmc(int S, int T) {
  26. while () {
  27. REP(i,,T) a[i]=INF,d[i]=1e15,inq[i]=;
  28. q.push(S),d[S]=;
  29. while (!q.empty()) {
  30. int x=q.front(); q.pop();
  31. inq[x] = ;
  32. for (auto t:g[x]) {
  33. auto e=E[t];
  34. if (e.w>&&d[e.to]>d[x]+e.f) {
  35. d[e.to]=d[x]+e.f;
  36. pre[e.to]=t;
  37. a[e.to]=min(a[x],e.w);
  38. if (!inq[e.to]) {
  39. inq[e.to]=;
  40. q.push(e.to);
  41. }
  42. }
  43. }
  44. }
  45. if (a[T]==INF) break;
  46. for (int u=T;u!=S;u=E[pre[u]].from) {
  47. E[pre[u]].w-=a[T];
  48. E[pre[u]^].w+=a[T];
  49. }
  50. mf+=a[T],mc+=a[T]*d[T];
  51. }
  52. }
  53.  
  54. int x[N],y[N];
  55. int main() {
  56. scanf("%d", &n);
  57. int S=*n+,T=S+;
  58. REP(i,,n) {
  59. scanf("%d%d",x+i,y+i);
  60. add(S,i,,);
  61. add(i+n,T,,);
  62. }
  63. REP(i,,n) REP(j,,n) if (y[i]>y[j]) {
  64. add(i,j+n,,sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])));
  65. }
  66. mfmc(S,T);
  67. if (mf!=n-) return puts("-1"),;
  68. printf("%.10lf\n",mc);
  69. }

6. 311E

大意: $n$个点, 颜色黑或白, 翻转第$i$个点的颜色花费$v_i$, $m$个需求, 要求一些点全白或全黑, 满足则有一定收益. 有些特殊需求若不满足则要花费$g$, 求最大收益.

最大权闭合子图问题, 最大收益转为总收益减去最小割. $S$连黑点和黑需求, 白点和白需求连$T$, 再对每个需求关系连一下边即可.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. using namespace std;
  6.  
  7. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  8. int n, m, g, a[N], b[N];
  9. struct edge {
  10. int to,w,next;
  11. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  12. } e[N];
  13. int head[N], dep[N], vis[N], cur[N], cnt=;
  14. queue<int> Q;
  15. void add(int u, int v, int w) {
  16. e[++cnt] = edge(v,w,head[u]);
  17. head[u] = cnt;
  18. e[++cnt] = edge(u,,head[v]);
  19. head[v] = cnt;
  20. }
  21. int bfs() {
  22. REP(i,,n+m) dep[i]=INF,vis[i]=,cur[i]=head[i];
  23. dep[S]=INF,vis[S]=,cur[S]=head[S];
  24. dep[T]=INF,vis[T]=,cur[T]=head[T];
  25. dep[S]=,Q.push(S);
  26. while (Q.size()) {
  27. int u = Q.front(); Q.pop();
  28. for (int i=head[u]; i; i=e[i].next) {
  29. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  30. dep[e[i].to]=dep[u]+;
  31. Q.push(e[i].to);
  32. }
  33. }
  34. }
  35. return dep[T]!=INF;
  36. }
  37. int dfs(int x, int w) {
  38. if (x==T) return w;
  39. int used = ;
  40. for (int i=cur[x]; i; i=e[i].next) {
  41. cur[x] = i;
  42. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  43. int f = dfs(e[i].to,min(w-used,e[i].w));
  44. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  45. if (used==w) break;
  46. }
  47. }
  48. return used;
  49. }
  50. int dinic() {
  51. int ans = ;
  52. while (bfs()) ans+=dfs(S,INF);
  53. return ans;
  54. }
  55.  
  56. int main() {
  57. scanf("%d%d%d", &n, &m, &g);
  58. REP(i,,n) scanf("%d",a+i);
  59. REP(i,,n) scanf("%d",b+i);
  60. REP(i,,n) {
  61. if (a[i]) add(S,i,b[i]);
  62. else add(i,T,b[i]);
  63. }
  64. int sum = ;
  65. REP(i,,m) {
  66. int c,w,k,t,f;
  67. scanf("%d%d%d",&c,&w,&k);
  68. sum += w;
  69. while (k--) {
  70. scanf("%d", &t);
  71. if (c) add(i+n,t,INF);
  72. else add(t,i+n,INF);
  73. }
  74. scanf("%d", &f);
  75. if (f) f = g;
  76. if (c) add(S,i+n,f+w);
  77. else add(i+n,T,f+w);
  78. }
  79. printf("%d\n",sum-dinic());
  80. }

7. 316C

大意: 给定$n*m$矩阵, $n*m$为偶数, $[1,\frac{nm}{2}]$每个数均出现$2$次, 求最少交换数使得相同数字相邻.

二分图最佳完美匹配, 每个点向相邻格子连边, 同色连费用0, 异色连费用1, 求出费用最小的完美匹配即为答案

  1. #include <iostream>
  2. #include <queue>
  3. #define REP(i,a,b) for(int i=a;i<=b;++i)
  4. using namespace std;
  5. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  6. int n, m, flow, cost;
  7. struct edge {
  8. int to,w,v,next;
  9. edge(int to=,int w=,int v=,int next=):to(to),v(v),w(w),next(next){}
  10. } e[N];
  11. int head[N], dep[N], vis[N], cur[N], f[N], cnt=;
  12. pair<int,int> pre[N];
  13. queue<int> Q;
  14. void add(int u, int v, int w, int k) {
  15. e[++cnt] = edge(v,w,k,head[u]);
  16. head[u] = cnt;
  17. e[++cnt] = edge(u,,-k,head[v]);
  18. head[v] = cnt;
  19. }
  20. int spfa() {
  21. REP(i,,n*m) f[i]=dep[i]=INF,vis[i]=;
  22. f[S]=dep[S]=f[T]=dep[T]=INF;
  23. dep[S]=,Q.push(S);
  24. while (Q.size()) {
  25. int u = Q.front(); Q.pop();
  26. vis[u] = ;
  27. for (int i=head[u]; i; i=e[i].next) {
  28. if (dep[e[i].to]>dep[u]+e[i].v&&e[i].w) {
  29. dep[e[i].to]=dep[u]+e[i].v;
  30. pre[e[i].to]=pair<int,int>(u,i);
  31. f[e[i].to]=min(f[u],e[i].w);
  32. if (!vis[e[i].to]) {
  33. vis[e[i].to]=;
  34. Q.push(e[i].to);
  35. }
  36. }
  37. }
  38. }
  39. return dep[T]!=INF;
  40. }
  41. int dfs(int x, int w) {
  42. if (x==T) return w;
  43. int used = ;
  44. for (int i=cur[x]; i; i=e[i].next) {
  45. cur[x] = i;
  46. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  47. int f = dfs(e[i].to,min(w-used,e[i].w));
  48. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  49. if (used==w) break;
  50. }
  51. }
  52. return used;
  53. }
  54. void EK(){
  55. while(spfa()) {
  56. int w = f[T];
  57. for (int u=T; u!=S; u=pre[u].first) {
  58. e[pre[u].second].w-=w;
  59. e[pre[u].second^].w+=w;
  60. }
  61. flow += w, cost += w*dep[T];
  62. }
  63. }
  64. int a[][];
  65. const int dx[]={,,-,};
  66. const int dy[]={-,,,};
  67. int ID(int x, int y) {
  68. return (x-)*m+y;
  69. }
  70. int main() {
  71. scanf("%d%d", &n, &m);
  72. REP(i,,n) REP(j,,m) scanf("%d",a[i]+j);
  73. REP(i,,n) REP(j,,m) {
  74. if (i!=n) {
  75. int x=ID(i,j),y=ID(i+,j);
  76. if (i+j&) swap(x,y);
  77. add(x,y,,a[i][j]!=a[i+][j]);
  78. }
  79. if (j!=m) {
  80. int x=ID(i,j),y=ID(i,j+);
  81. if (i+j&) swap(x,y);
  82. add(x,y,,a[i][j]!=a[i][j+]);
  83. }
  84. if (i+j&) add(ID(i,j),T,,);
  85. else add(S,ID(i,j),,);
  86. }
  87. EK();
  88. printf("%d\n",cost);
  89. }

8. 321B

大意: 对手$n$只怪, 你有$m$只怪, 现在是你的回合. 对面怪全有嘲讽, 分为攻击怪和防御怪. 若你攻击对面攻击怪, 要满足你怪的能力不少于对面, 攻击后对面怪死亡, 对英雄伤害为能力差. 若你攻击对面防御怪, 要满足你怪的能力大于对面, 攻击后对面怪死亡, 对英雄伤害$0$. 若对面没怪可以直接攻击对面英雄, 伤害为你的怪的能力值. 求英雄造成的最大伤害.

不攻击英雄的情况贪心判掉. 攻击英雄的情况, 显然是一个最大带权匹配问题, 用费用流或者$KM$即可.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. using namespace std;
  6. const int N = 1e6+, INF = 0x3f3f3f3f, S = N-, T = N-;
  7. int n, m, flow, cost;
  8. struct edge {
  9. int to,w,v,next;
  10. edge(int to=,int w=,int v=,int next=):to(to),w(w),v(v),next(next){}
  11. } e[N];
  12. int head[N], dep[N], vis[N], cur[N], f[N], cnt=;
  13. int pre[N],pre2[N];
  14. queue<int> Q;
  15. void add(int u, int v, int w, int k) {
  16. e[++cnt] = edge(v,w,k,head[u]);
  17. head[u] = cnt;
  18. e[++cnt] = edge(u,,-k,head[v]);
  19. head[v] = cnt;
  20. }
  21. int spfa() {
  22. REP(i,,n+m) f[i]=dep[i]=INF,vis[i]=;
  23. f[S]=dep[S]=f[T]=dep[T]=INF;
  24. dep[S]=,Q.push(S);
  25. while (Q.size()) {
  26. int u = Q.front(); Q.pop();
  27. vis[u] = ;
  28. for (int i=head[u]; i; i=e[i].next) {
  29. if (dep[e[i].to]>dep[u]+e[i].v&&e[i].w) {
  30. dep[e[i].to]=dep[u]+e[i].v;
  31. pre[e[i].to]=u,pre2[e[i].to]=i;
  32. f[e[i].to]=min(f[u],e[i].w);
  33. if (!vis[e[i].to]) {
  34. vis[e[i].to]=;
  35. Q.push(e[i].to);
  36. }
  37. }
  38. }
  39. }
  40. return dep[T]!=INF;
  41. }
  42. void EK(){
  43. while(spfa()) {
  44. int w = f[T];
  45. for (int u=T; u!=S; u=pre[u]) {
  46. e[pre2[u]].w-=w;
  47. e[pre2[u]^].w+=w;
  48. }
  49. flow += w, cost += w*dep[T];
  50. }
  51. }
  52. int a[N], b[N], c[N];
  53. char s[][];
  54.  
  55. int main() {
  56. scanf("%d%d", &n, &m);
  57. REP(i,,n) scanf("%s%d",s[i],a+i);
  58. int sum = ;
  59. REP(i,,m) scanf("%d",b+i),sum+=b[i];
  60. REP(i,,m) add(S,i,,);
  61. REP(i,,n) add(i+m,T,,);
  62. REP(i,,m) REP(j,,n) {
  63. if (s[j][]=='A') {
  64. if (b[i]>=a[j]) add(i,j+m,,a[j]);
  65. else add(i,j+m,,1e6);
  66. }
  67. else {
  68. if (b[i]>a[j]) add(i,j+m,,b[i]);
  69. else add(i,j+m,,1e6);
  70. }
  71. }
  72. EK();
  73. int ans = sum-cost;
  74. REP(i,,n) if (s[i][]=='A') c[++*c]=a[i];
  75. sort(b+,b++m,greater<int>());
  76. sort(c+,c++*c);
  77. int ret = ;
  78. REP(i,,min(m,*c)) ret += max(,b[i]-c[i]);
  79. printf("%d\n",max(ans,ret));
  80. }

9. 343E

最小割树

10. 362E

大意: 给定$n$个点的网络图, 每次操作选一条边流量$+1$, 最多$k$次, 求最大流.

先求一次最大流, 然后对残量网络上每条边加一条容量$k$, 费用为$1$的边, 再跑一次费用流, 当费用达到$k$时停止.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. using namespace std;
  6. typedef pair<int,int> pii;
  7. const int N = 5e4+,INF=0x3f3f3f3f;
  8. int n,m,cost,flow,S,T;
  9. struct edge {
  10. int to,next,w,v;
  11. edge(int to=,int next=,int w=,int v=):to(to),next(next),w(w),v(v){}
  12. } e[N];
  13. int head[N],dep[N],vis[N],f[N],cnt=;
  14. pii pre[N];
  15. queue<int> Q;
  16.  
  17. int spfa() {
  18. REP(i,,n) f[i]=dep[i]=INF,vis[i]=;
  19. dep[S]=,Q.push(S);
  20. while (Q.size()) {
  21. int u = Q.front(); Q.pop();
  22. vis[u] = ;
  23. for (int i=head[u]; i; i=e[i].next) {
  24. if (e[i].w&&dep[e[i].to]>dep[u]+e[i].v) {
  25. dep[e[i].to]=dep[u]+e[i].v;
  26. pre[e[i].to]=pii(u,i);
  27. f[e[i].to]=min(f[u],e[i].w);
  28. if (!vis[e[i].to]) {
  29. vis[e[i].to]=;
  30. Q.push(e[i].to);
  31. }
  32. }
  33. }
  34. }
  35. return cost+dep[T]<=m;
  36. }
  37. void EK(){
  38. while(spfa()) {
  39. int w = f[T];
  40. if (cost+(long long)w*dep[T]>m) w = (m-cost)/dep[T];
  41. for (int u=T; u!=S; u=pre[u].first) {
  42. e[pre[u].second].w-=w;
  43. e[pre[u].second^].w+=w;
  44. }
  45. flow += w, cost += w*dep[T];
  46. }
  47. }
  48. void add(int x,int y,int k,int v) {
  49. e[++cnt] = edge(y,head[x],k,v);
  50. head[x] = cnt;
  51. e[++cnt] = edge(x,head[y],,-v);
  52. head[y] = cnt;
  53. }
  54.  
  55. int a[][];
  56. int main() {
  57. scanf("%d%d", &n, &m);
  58. S=,T=n;
  59. REP(i,,n) REP(j,,n) {
  60. scanf("%d", a[i]+j);
  61. if (a[i][j]) add(i,j,a[i][j],);
  62. }
  63. EK();
  64. REP(i,,n) REP(j,,n) {
  65. if (a[i][j]) add(i,j,m,);
  66. }
  67. EK();
  68. printf("%d\n", flow);
  69. }

11. 434D

大意: $n$个数, 范围$[l,r]$, 第$i$个数若选$x$则有贡献$a_ix^2+b_ix+c$, 有$m$个限制$(u,v,d)$, 表示$x_u\le x_v+d$, 求贡献最大值.

最小割经典应用, 建图可以参照[HNOI2013]切糕. 本题是要求最大值, 流量取相反数, 转为最小, 但是因为流量不能有负数, 再全部增加一个值, 转为正.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #include <map>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. using namespace std;
  7. typedef pair<int,int> pii;
  8.  
  9. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  10. int tot;
  11. map<pii,int> mp;
  12. int ID(int x, int y) {
  13. if (mp.count(pii(x,y))) return mp[pii(x,y)];
  14. return mp[pii(x,y)] = ++tot;
  15. }
  16. struct edge {
  17. int to,w,next;
  18. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  19. } e[N];
  20. int head[N], dep[N], vis[N], cur[N], cnt=;
  21. queue<int> Q;
  22. int bfs() {
  23. REP(i,,tot) dep[i]=INF,vis[i]=,cur[i]=head[i];
  24. dep[S]=INF,vis[S]=,cur[S]=head[S];
  25. dep[T]=INF,vis[T]=,cur[T]=head[T];
  26. dep[S]=,Q.push(S);
  27. while (Q.size()) {
  28. int u = Q.front(); Q.pop();
  29. for (int i=head[u]; i; i=e[i].next) {
  30. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  31. dep[e[i].to]=dep[u]+;
  32. Q.push(e[i].to);
  33. }
  34. }
  35. }
  36. return dep[T]!=INF;
  37. }
  38. int dfs(int x, int w) {
  39. if (x==T) return w;
  40. int used = ;
  41. for (int i=cur[x]; i; i=e[i].next) {
  42. cur[x] = i;
  43. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  44. int f = dfs(e[i].to,min(w-used,e[i].w));
  45. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  46. if (used==w) break;
  47. }
  48. }
  49. return used;
  50. }
  51. int dinic() {
  52. int ans = ;
  53. while (bfs()) ans+=dfs(S,INF);
  54. return ans;
  55. }
  56. void add(int u, int v, int w) {
  57. e[++cnt] = edge(v,w,head[u]);
  58. head[u] = cnt;
  59. e[++cnt] = edge(u,,head[v]);
  60. head[v] = cnt;
  61. }
  62.  
  63. int n,m,a[N],b[N],c[N],l[N],r[N];
  64. int f(int i, int x) {
  65. return a[i]*x*x+b[i]*x+c[i];
  66. }
  67.  
  68. int main() {
  69. scanf("%d%d", &n, &m);
  70. REP(i,,n) scanf("%d%d%d",a+i,b+i,c+i);
  71. int ma = -1e9;
  72. REP(i,,n) {
  73. scanf("%d%d", l+i, r+i);
  74. REP(j,l[i],r[i]) ma=max(ma,f(i,j));
  75. }
  76. REP(i,,n) {
  77. --l[i],++r[i];
  78. add(S,ID(i,l[i]),INF);
  79. REP(j,l[i]+,r[i]-) add(ID(i,j-),ID(i,j),-f(i,j));
  80. add(ID(i,r[i]-),ID(i,r[i]),INF),add(ID(i,r[i]),T,INF);
  81. }
  82. REP(i,,m) {
  83. int u,v,d;
  84. scanf("%d%d%d",&u,&v,&d);
  85. REP(j,l[v],r[v]) {
  86. int k = j+d;
  87. if (l[u]<=k&&k<=r[u]) {
  88. add(ID(u,k),ID(v,j),INF);
  89. }
  90. }
  91. }
  92. printf("%d\n", -dinic());
  93. }

12. 491C

大意:给定两个长为$n$的串, 求改变第一个字符串的字母映射关系, 使得两个串对应位置相等的个数最大.

裸的最大带权匹配.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #include <map>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. using namespace std;
  7. const int N = 2e6+, INF = 0x3f3f3f3f, S = N-, T = N-;
  8. int flow, cost, k, n;
  9. struct edge {
  10. int to,w,v,next;
  11. edge(int to=,int w=,int v=,int next=):to(to),w(w),v(v),next(next){}
  12. } e[N];
  13. int head[N], dep[N], vis[N], cur[N], f[N], cnt=;
  14. int pre[N],pre2[N];
  15. queue<int> Q;
  16. int spfa() {
  17. REP(i,,*k) f[i]=dep[i]=INF,vis[i]=;
  18. f[S]=dep[S]=f[T]=dep[T]=INF;
  19. dep[S]=,Q.push(S);
  20. while (Q.size()) {
  21. int u = Q.front(); Q.pop();
  22. vis[u] = ;
  23. for (int i=head[u]; i; i=e[i].next) {
  24. if (dep[e[i].to]>dep[u]+e[i].v&&e[i].w) {
  25. dep[e[i].to]=dep[u]+e[i].v;
  26. pre[e[i].to]=u,pre2[e[i].to]=i;
  27. f[e[i].to]=min(f[u],e[i].w);
  28. if (!vis[e[i].to]) {
  29. vis[e[i].to]=;
  30. Q.push(e[i].to);
  31. }
  32. }
  33. }
  34. }
  35. return dep[T]!=INF;
  36. }
  37. void EK(){
  38. while(spfa()) {
  39. int w = f[T];
  40. for (int u=T; u!=S; u=pre[u]) {
  41. e[pre2[u]].w-=w;
  42. e[pre2[u]^].w+=w;
  43. }
  44. flow += w, cost += w*dep[T];
  45. }
  46. }
  47. void add(int u, int v, int w, int k) {
  48. e[++cnt] = edge(v,w,k,head[u]);
  49. head[u] = cnt;
  50. e[++cnt] = edge(u,,-k,head[v]);
  51. head[v] = cnt;
  52. }
  53.  
  54. int a[][],b[][],ans[N],ID[N];
  55. char s[N],ss[N],t[N],val[N];
  56.  
  57. int main() {
  58. scanf("%d%d", &n, &k);
  59. REP(i,,min(,k)) ID[val[i]=i-+'a']=i;
  60. REP(i,,k) ID[val[i]=i-+'A']=i;
  61. scanf("%s%s",s+,ss+);
  62. REP(i,,n) ++a[ID[s[i]]][ID[ss[i]]];
  63. REP(i,,k) add(S,i,,),add(i+k,T,,);
  64. REP(i,,k) REP(j,,k) b[i][j]=cnt+,add(i,j+k,,-a[i][j]);
  65. EK();
  66. printf("%d\n", -cost);
  67. REP(i,,k) REP(j,,k) if (!e[b[i][j]].w) ans[i]=val[j];
  68. REP(i,,k) putchar(ans[i]);puts("");
  69. }

13. 498C

大意: 给定序列$a$, $m$个二元组$(x,y)$, 保证$x+y$为奇数, 每次操作任选一个二元组$(x,y)$, 选择一个$k>1$, 且$k$能整除$a_x$和$a_y$, 然后将$a_x,a_y$除以$k$, 求最多进行多少次操作.

裸的最大流.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cmath>
  4. #include <map>
  5. #include <queue>
  6. #define REP(i,a,n) for(int i=a;i<=n;++i)
  7. #define x first
  8. #define y second
  9. using namespace std;
  10. typedef pair<int,int> pii;
  11. inline int rd() {int x=;char p=getchar();while(p<''||p>'')p=getchar();while(p>=''&&p<='')x=x*+p-'',p=getchar();return x;}
  12.  
  13. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  14. int n,m,tot;
  15. struct edge {
  16. int to,w,next;
  17. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  18. } e[N];
  19. int head[N], dep[N], vis[N], cur[N], cnt=;
  20. queue<int> Q;
  21. int bfs() {
  22. REP(i,,tot) dep[i]=INF,vis[i]=,cur[i]=head[i];
  23. dep[S]=INF,vis[S]=,cur[S]=head[S];
  24. dep[T]=INF,vis[T]=,cur[T]=head[T];
  25. dep[S]=,Q.push(S);
  26. while (Q.size()) {
  27. int u = Q.front(); Q.pop();
  28. for (int i=head[u]; i; i=e[i].next) {
  29. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  30. dep[e[i].to]=dep[u]+;
  31. Q.push(e[i].to);
  32. }
  33. }
  34. }
  35. return dep[T]!=INF;
  36. }
  37. int dfs(int x, int w) {
  38. if (x==T) return w;
  39. int used = ;
  40. for (int i=cur[x]; i; i=e[i].next) {
  41. cur[x] = i;
  42. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  43. int f = dfs(e[i].to,min(w-used,e[i].w));
  44. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  45. if (used==w) break;
  46. }
  47. }
  48. return used;
  49. }
  50. int dinic() {
  51. int ans = ;
  52. while (bfs()) ans+=dfs(S,INF);
  53. return ans;
  54. }
  55. void add(int u, int v, int w) {
  56. e[++cnt] = edge(v,w,head[u]);
  57. head[u] = cnt;
  58. e[++cnt] = edge(u,,head[v]);
  59. head[v] = cnt;
  60. }
  61. map<int,int> f[N];
  62. map<pii,int> mp;
  63. int ID(int x, int y) {
  64. if (mp.count(pii(x,y))) return mp[pii(x,y)];
  65. return mp[pii(x,y)] = ++tot;
  66. }
  67. map<int,int> fac(int x) {
  68. int mx = sqrt(x+0.5);
  69. map<int,int> v;
  70. REP(i,,mx) {
  71. while (x%i==) x/=i,++v[i];
  72. }
  73. if (x>) ++v[x];
  74. return v;
  75. }
  76.  
  77. int main() {
  78. scanf("%d%d", &n, &m);
  79. REP(i,,n) {
  80. f[i]=fac(rd());
  81. if (i&) for (auto t:f[i]) add(ID(i,t.x),T,t.y);
  82. else for (auto t:f[i]) add(S,ID(i,t.x),t.y);
  83. }
  84. REP(i,,m) {
  85. int u=rd(),v=rd();
  86. if (u&) swap(u,v);
  87. for (auto t:f[u]) {
  88. if (f[v].count(t.x)) add(ID(u,t.x),ID(v,t.x),INF);
  89. }
  90. }
  91. printf("%d\n", dinic());
  92. }

14. 510E

大意: n只狐狸, 要求分成若干个环, 每个环的狐狸不少于三只, 相邻狐狸年龄和为素数.

年龄大于$1$, 那么两个数和为素数必然是一奇一偶, 奇偶分开建图跑最大流即可.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cmath>
  4. #include <map>
  5. #include <queue>
  6. #define REP(i,a,n) for(int i=a;i<=n;++i)
  7. #define pb push_back
  8. #define x first
  9. #define y second
  10. using namespace std;
  11. typedef pair<int,int> pii;
  12. inline int rd() {int x=;char p=getchar();while(p<''||p>'')p=getchar();while(p>=''&&p<='')x=x*+p-'',p=getchar();return x;}
  13.  
  14. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  15. int n;
  16. struct edge {
  17. int to,w,next;
  18. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  19. } e[N];
  20. int head[N], dep[N], vis[N], cur[N], cnt=;
  21. queue<int> Q;
  22. int bfs() {
  23. REP(i,,n) dep[i]=INF,vis[i]=,cur[i]=head[i];
  24. dep[S]=INF,vis[S]=,cur[S]=head[S];
  25. dep[T]=INF,vis[T]=,cur[T]=head[T];
  26. dep[S]=,Q.push(S);
  27. while (Q.size()) {
  28. int u = Q.front(); Q.pop();
  29. for (int i=head[u]; i; i=e[i].next) {
  30. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  31. dep[e[i].to]=dep[u]+;
  32. Q.push(e[i].to);
  33. }
  34. }
  35. }
  36. return dep[T]!=INF;
  37. }
  38. int dfs(int x, int w) {
  39. if (x==T) return w;
  40. int used = ;
  41. for (int i=cur[x]; i; i=e[i].next) {
  42. cur[x] = i;
  43. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  44. int f = dfs(e[i].to,min(w-used,e[i].w));
  45. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  46. if (used==w) break;
  47. }
  48. }
  49. return used;
  50. }
  51. int dinic() {
  52. int ans = ;
  53. while (bfs()) ans+=dfs(S,INF);
  54. return ans;
  55. }
  56. void add(int u, int v, int w) {
  57. e[++cnt] = edge(v,w,head[u]);
  58. head[u] = cnt;
  59. e[++cnt] = edge(u,,head[v]);
  60. head[v] = cnt;
  61. }
  62.  
  63. int f[N],a[N];
  64. vector<int> g[N],ans[N];
  65. void seive(int n) {
  66. int mx = sqrt(n+0.5);
  67. REP(i,,mx) if (!f[i]) {
  68. for (int j=i*i; j<=n; j+=i) f[j] = ;
  69. }
  70. }
  71.  
  72. int main() {
  73. seive();
  74. scanf("%d", &n);
  75. REP(i,,n) {
  76. if ((a[i]=rd())&) add(S,i,);
  77. else add(i,T,);
  78. }
  79. REP(i,,n) if (a[i]&) REP(j,,n) if (a[j]&^) {
  80. if (!f[a[i]+a[j]]) add(i,j,);
  81. }
  82. if (dinic()!=n) return puts("Impossible"),;
  83. REP(i,,n) if (a[i]&) {
  84. for (int t=head[i]; t; t=e[t].next) {
  85. if (!e[t].w&&e[t].to<=n) {
  86. g[i].pb(e[t].to);
  87. g[e[t].to].pb(i);
  88. }
  89. }
  90. }
  91. REP(i,,n) vis[i] = ;
  92. int cnt = ;
  93. REP(i,,n) if (!vis[i]) {
  94. ++cnt;
  95. int j = i;
  96. while () {
  97. vis[j] = ;
  98. ans[cnt].pb(j);
  99. if (vis[g[j][]]&&vis[g[j][]]) break;
  100. if (vis[g[j][]]) j=g[j][];
  101. else j=g[j][];
  102. }
  103. }
  104. printf("%d\n", cnt);
  105. REP(i,,cnt) {
  106. printf("%d ", (int)ans[i].size());
  107. for (int j:ans[i]) printf("%d ",j);
  108. puts("");
  109. }
  110. }

15. 513F

大意: $n*m$的矩阵, 每个格子能住两个人, 给定每个人的位置以及移动速度, 求最短多少时间, 能使所有人都和一个异性分到一个房间.

二分答案, 建图, 看最大流是否满流.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #include <string.h>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. using namespace std;
  7. typedef long long ll;
  8. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  9. struct edge {
  10. int to,w,next;
  11. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  12. } e[N];
  13. int head[N], dep[N], vis[N], cur[N], cnt=;
  14. queue<int> Q;
  15. int bfs(int n) {
  16. REP(i,,n) dep[i]=INF,vis[i]=,cur[i]=head[i];
  17. dep[S]=INF,vis[S]=,cur[S]=head[S];
  18. dep[T]=INF,vis[T]=,cur[T]=head[T];
  19. dep[S]=,Q.push(S);
  20. while (Q.size()) {
  21. int u = Q.front(); Q.pop();
  22. for (int i=head[u]; i; i=e[i].next) {
  23. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  24. dep[e[i].to]=dep[u]+;
  25. Q.push(e[i].to);
  26. }
  27. }
  28. }
  29. return dep[T]!=INF;
  30. }
  31. int dfs(int x, int w) {
  32. if (x==T) return w;
  33. int used = ;
  34. for (int i=cur[x]; i; i=e[i].next) {
  35. cur[x] = i;
  36. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  37. int f = dfs(e[i].to,min(w-used,e[i].w));
  38. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  39. if (used==w) break;
  40. }
  41. }
  42. return used;
  43. }
  44. int dinic(int n) {
  45. int ans = ;
  46. while (bfs(n)) ans+=dfs(S,INF);
  47. return ans;
  48. }
  49. void add(int u, int v, int w) {
  50. e[++cnt] = edge(v,w,head[u]);
  51. head[u] = cnt;
  52. e[++cnt] = edge(u,,head[v]);
  53. head[v] = cnt;
  54. }
  55.  
  56. int n,m,x,y;
  57. struct _ {int x,y,t;} h, a[N], b[N];
  58. char s[][];
  59. int v[][];
  60. int ID(int x, int y) {
  61. return (x-)*m+y;
  62. }
  63. const int dx[]={,,-,};
  64. const int dy[]={-,,,};
  65. int chk(ll tot) {
  66. cnt = ;
  67. REP(i,,*x+*n*m) head[i]=;
  68. head[S]=head[T]=;
  69. queue<_> q;
  70. REP(i,,x) {
  71. add(S,i,);
  72. q.push({a[i].x,a[i].y,});
  73. memset(v,,sizeof v);
  74. while (q.size()) {
  75. _ u = q.front(); q.pop();
  76. if (s[u.x][u.y]=='#'||v[u.x][u.y]) continue;
  77. if (a[i].t&&u.t>tot/a[i].t) continue;
  78. v[u.x][u.y] = ;
  79. REP(k,,) {
  80. int xx=u.x+dx[k],yy=u.y+dy[k];
  81. if (<=xx&&xx<=n&&<=yy&&yy<=m) {
  82. q.push({xx,yy,u.t+});
  83. }
  84. }
  85. }
  86. REP(j,,n) REP(k,,m) if (v[j][k]) add(i,ID(j,k)+*x,);
  87. }
  88. REP(i,,x) {
  89. add(i+x,T,);
  90. q.push({b[i].x,b[i].y,});
  91. memset(v,,sizeof v);
  92. while (q.size()) {
  93. _ u = q.front(); q.pop();
  94. if (s[u.x][u.y]=='#'||v[u.x][u.y]) continue;
  95. if (b[i].t&&u.t>tot/b[i].t) continue;
  96. v[u.x][u.y] = ;
  97. REP(k,,) {
  98. int xx=u.x+dx[k],yy=u.y+dy[k];
  99. if (<=xx&&xx<=n&&<=yy&&yy<=m) {
  100. q.push({xx,yy,u.t+});
  101. }
  102. }
  103. }
  104. REP(j,,n) REP(k,,m) if (v[j][k]) add(ID(j,k)+*x+n*m,i+x,);
  105. }
  106. REP(i,,n) REP(j,,m) if (s[i][j]!='#') add(ID(i,j)+*x,ID(i,j)+*x+n*m,);
  107. return dinic(*x+*n*m)==x;
  108. }
  109.  
  110. int main() {
  111. scanf("%d%d%d%d", &n, &m, &x, &y);
  112. if (abs(x-y)!=) return puts("-1"),;
  113. REP(i,,n) scanf("%s",s[i]+);
  114. scanf("%d%d%d",&h.x,&h.y,&h.t);
  115. REP(i,,x) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].t);
  116. REP(i,,y) scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].t);
  117. if (x>y) b[++y]=h;
  118. else a[++x]=h;
  119. ll l=,r=1e18,ans=-;
  120. while (l<=r) {
  121. ll mid = (l+r)/;
  122. if (chk(mid)) ans=mid,r=mid-;
  123. else l=mid+;
  124. }
  125. printf("%lld\n", ans);
  126. }

16. 546E

大意: 给定无向图, 点$i$有$a_i$个士兵, 士兵只能移动不超过$1$, 求是否能使点$i$有$b_i$个士兵.

每个点拆成入点和出点, $S$连入点, 出点连$T$, 入点连接所有距离不超过$1$的出点, 判断能否满流即可.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. using namespace std;
  6. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  7. int n, m, s1, s2, ans[][];
  8. struct edge {
  9. int to,w,next;
  10. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  11. } e[N];
  12. int head[N], dep[N], vis[N], cur[N], cnt=;
  13. queue<int> Q;
  14. int bfs() {
  15. REP(i,,*n) dep[i]=INF,vis[i]=,cur[i]=head[i];
  16. dep[S]=INF,vis[S]=,cur[S]=head[S];
  17. dep[T]=INF,vis[T]=,cur[T]=head[T];
  18. dep[S]=,Q.push(S);
  19. while (Q.size()) {
  20. int u = Q.front(); Q.pop();
  21. for (int i=head[u]; i; i=e[i].next) {
  22. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  23. dep[e[i].to]=dep[u]+;
  24. Q.push(e[i].to);
  25. }
  26. }
  27. }
  28. return dep[T]!=INF;
  29. }
  30. int dfs(int x, int w) {
  31. if (x==T) return w;
  32. int used = ;
  33. for (int i=cur[x]; i; i=e[i].next) {
  34. cur[x] = i;
  35. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  36. int f = dfs(e[i].to,min(w-used,e[i].w));
  37. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  38. if (used==w) break;
  39. }
  40. }
  41. return used;
  42. }
  43. int dinic() {
  44. int ans = ;
  45. while (bfs()) ans+=dfs(S,INF);
  46. return ans;
  47. }
  48. void add(int u, int v, int w) {
  49. e[++cnt] = edge(v,w,head[u]);
  50. head[u] = cnt;
  51. e[++cnt] = edge(u,,head[v]);
  52. head[v] = cnt;
  53. }
  54. int main() {
  55. scanf("%d%d", &n, &m);
  56. REP(i,,n) {
  57. int t;
  58. scanf("%d", &t);
  59. s1 += t;
  60. add(S,i,t),add(i,i+n,INF);
  61. }
  62. REP(i,,n) {
  63. int t;
  64. scanf("%d", &t);
  65. s2 += t;
  66. add(i+n,T,t);
  67. }
  68. while (m--) {
  69. int u, v;
  70. scanf("%d%d", &u, &v);
  71. add(u,v+n,INF),add(v,u+n,INF);
  72. }
  73. if (s1!=s2||dinic()!=s1) return puts("NO"),;
  74. puts("YES");
  75. REP(i,,n) {
  76. for (int j=head[i]; j; j=e[j].next) {
  77. if (<=e[j].to-n&&e[j].to-n<=n) ans[i][e[j].to-n] = e[j^].w;
  78. }
  79. }
  80. REP(i,,n) {
  81. REP(j,,n) printf("%d ",ans[i][j]);
  82. puts("");
  83. }
  84. }

17. 611H

18. 628F

大意: $n$元素集合, $n$被$5$整除, 模$5$后每种余数个数相同, 每个数范围在$[1,b]$内. 有$q$个限制$(x,y)$, 要求在$[1,x]$中恰好有$y$个数. 求是否能构造出该集合.

$q$个限制可以做一下差, 转化为$q$个不相交的区间$[l,r]$内恰有$y$个数, 然后就是很简单的建图了, 看能否满流即可.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. using namespace std;
  6. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  7. int n, b, q, a[N];
  8. struct edge {
  9. int to,w,next;
  10. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  11. } e[N];
  12. int head[N], dep[N], vis[N], cur[N], cnt=;
  13. queue<int> Q;
  14. int bfs() {
  15. REP(i,,*b+) dep[i]=INF,vis[i]=,cur[i]=head[i];
  16. dep[S]=INF,vis[S]=,cur[S]=head[S];
  17. dep[T]=INF,vis[T]=,cur[T]=head[T];
  18. dep[S]=,Q.push(S);
  19. while (Q.size()) {
  20. int u = Q.front(); Q.pop();
  21. for (int i=head[u]; i; i=e[i].next) {
  22. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  23. dep[e[i].to]=dep[u]+;
  24. Q.push(e[i].to);
  25. }
  26. }
  27. }
  28. return dep[T]!=INF;
  29. }
  30. int dfs(int x, int w) {
  31. if (x==T) return w;
  32. int used = ;
  33. for (int i=cur[x]; i; i=e[i].next) {
  34. cur[x] = i;
  35. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  36. int f = dfs(e[i].to,min(w-used,e[i].w));
  37. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  38. if (used==w) break;
  39. }
  40. }
  41. return used;
  42. }
  43. int dinic() {
  44. int ans = ;
  45. while (bfs()) ans+=dfs(S,INF);
  46. return ans;
  47. }
  48. void add(int u, int v, int w) {
  49. e[++cnt] = edge(v,w,head[u]);
  50. head[u] = cnt;
  51. e[++cnt] = edge(u,,head[v]);
  52. head[v] = cnt;
  53. }
  54.  
  55. int main() {
  56. scanf("%d%d%d", &n, &b, &q);
  57. REP(i,,b) {
  58. a[i] = -;
  59. add(i,*b++i%,);
  60. }
  61. REP(i,,) add(*b++i%,T,n/);
  62. REP(i,,q) {
  63. int x, y;
  64. scanf("%d%d", &x, &y);
  65. if (a[x]!=-&&a[x]!=y) return puts("unfair"),;
  66. a[x] = y;
  67. }
  68. if (a[b]!=-&&a[b]!=n) return puts("unfair"),;
  69. a[b] = n;
  70. int tot = , pre = ;
  71. REP(i,,b) if (a[i]!=-) {
  72. if (a[i]<tot) return puts("unfair"),;
  73. if (a[i]!=tot) {
  74. add(S,i+b,a[i]-tot);
  75. REP(j,pre+,i) add(i+b,j,);
  76. }
  77. tot = a[i], pre = i;
  78. }
  79. puts(dinic()==n?"fair":"unfair");
  80. }

19. 653D

大意: 给定有向图, 有$x$只熊, 每只熊重量相同, 从节点$1$走到节点$n$, 每条路经过熊的总重量不能超过边权, 求每只熊重量最大值.

裸的最大流.

  1. #include <iostream>
  2. #include <cmath>
  3. #include <cstdio>
  4. #include <queue>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. using namespace std;
  7. typedef long long ll;
  8. const double eps = 1e-;
  9. const int N = 1e6+, INF = 0x3f3f3f3f;
  10. int n, m, x, S, T;
  11. int a[N],b[N],c[N];
  12. struct edge {
  13. int to;
  14. ll w;
  15. int next;
  16. edge(int to=,ll w=,int next=):to(to),w(w),next(next){}
  17. } e[N];
  18. int head[N], dep[N], vis[N], cur[N], cnt=;
  19. queue<int> Q;
  20. int bfs() {
  21. REP(i,,n) dep[i]=INF,vis[i]=,cur[i]=head[i];
  22. dep[S]=,Q.push(S);
  23. while (Q.size()) {
  24. int u = Q.front(); Q.pop();
  25. for (int i=head[u]; i; i=e[i].next) {
  26. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  27. dep[e[i].to]=dep[u]+;
  28. Q.push(e[i].to);
  29. }
  30. }
  31. }
  32. return dep[T]!=INF;
  33. }
  34. ll dfs(int x, ll w) {
  35. if (x==T) return w;
  36. ll used = ;
  37. for (int i=cur[x]; i; i=e[i].next) {
  38. cur[x] = i;
  39. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  40. int f = dfs(e[i].to,min(w-used,e[i].w));
  41. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  42. if (used==w) break;
  43. }
  44. }
  45. return used;
  46. }
  47. ll dinic() {
  48. ll ans = ;
  49. while (bfs()) ans+=dfs(S,1e15);
  50. return ans;
  51. }
  52. void add(int u, int v, ll w) {
  53. e[++cnt] = edge(v,w,head[u]);
  54. head[u] = cnt;
  55. e[++cnt] = edge(u,,head[v]);
  56. head[v] = cnt;
  57. }
  58. int chk(double w) {
  59. w /= x;
  60. if (fabs(w)<=eps) return ;
  61. cnt = , S = , T = n;
  62. REP(i,,n) head[i] = ;
  63. REP(i,,m) add(a[i],b[i],c[i]/w);
  64. return dinic()>=x;
  65. }
  66.  
  67. int main() {
  68. scanf("%d%d%d", &n, &m, &x);
  69. REP(i,,m) scanf("%d%d%d",a+i,b+i,c+i);
  70. double l=,r=1e11,ans;
  71. REP(i,,) {
  72. double mid=(l+r)/;
  73. if (chk(mid)) ans=mid,l=mid+eps;
  74. else r=mid-eps;
  75. }
  76. printf("%.10000lf\n", ans);
  77. }

20. 704D

大意: 给定平面上$n$个点, 每个点染为红色花费$r$, 蓝色花费$b$. 给定$m$个限制$(t,l,d)$, $t$为$1$表示直线$x=l$上红蓝点差不超过$d$, 否则是$y=l$上红蓝点差不超过$d$, 求最少花费.

21. 708D

22. 717G

大意: 给定一个串$s$, $n$个模式串, 模式串与主串匹配可以获得一定权值, 主串每个位置最多匹配$x$个模式串, 求最大权值.

裸的最长$k$重区间集, 费用流跑一下即可.

  1. #include <iostream>
  2. #include <string.h>
  3. #include <cstdio>
  4. #include <queue>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. using namespace std;
  7.  
  8. const int N = 1e6+, INF = 0x3f3f3f3f, S = N-, T = N-;
  9. int flow, cost;
  10. int n,m,x,w[N];
  11. char s[],p[][];
  12. struct edge {
  13. int to,w,v,next;
  14. edge(int to=,int w=,int v=,int next=):to(to),w(w),v(v),next(next){}
  15. } e[N];
  16. int head[N], dep[N], vis[N], cur[N], f[N], cnt=;
  17. int pre[N],pre2[N];
  18. queue<int> Q;
  19. int spfa() {
  20. REP(i,,n+) f[i]=dep[i]=INF,vis[i]=;
  21. f[S]=dep[S]=f[T]=dep[T]=INF;
  22. dep[S]=,Q.push(S);
  23. while (Q.size()) {
  24. int u = Q.front(); Q.pop();
  25. vis[u] = ;
  26. for (int i=head[u]; i; i=e[i].next) {
  27. if (dep[e[i].to]>dep[u]+e[i].v&&e[i].w) {
  28. dep[e[i].to]=dep[u]+e[i].v;
  29. pre[e[i].to]=u,pre2[e[i].to]=i;
  30. f[e[i].to]=min(f[u],e[i].w);
  31. if (!vis[e[i].to]) {
  32. vis[e[i].to]=;
  33. Q.push(e[i].to);
  34. }
  35. }
  36. }
  37. }
  38. return dep[T]!=INF;
  39. }
  40. void EK(){
  41. while(spfa()) {
  42. int w = f[T];
  43. for (int u=T; u!=S; u=pre[u]) {
  44. e[pre2[u]].w-=w;
  45. e[pre2[u]^].w+=w;
  46. }
  47. flow += w, cost += w*dep[T];
  48. }
  49. }
  50. void add(int u, int v, int w, int k) {
  51. e[++cnt] = edge(v,w,k,head[u]);
  52. head[u] = cnt;
  53. e[++cnt] = edge(u,,-k,head[v]);
  54. head[v] = cnt;
  55. }
  56.  
  57. int main() {
  58. scanf("%d%s",&n,s);
  59. scanf("%d",&m);
  60. REP(i,,m) scanf("%s%d",p[i],w+i);
  61. scanf("%d",&x);
  62. add(S,,x,);
  63. REP(i,,n) add(i,i+,x,);
  64. add(n+,T,x,);
  65. REP(i,,m) {
  66. int len = strlen(p[i]);
  67. REP(j,,n-) {
  68. if (strncmp(s+j,p[i],len)==) add(j+,j++len,,-w[i]);
  69. }
  70. }
  71. EK();
  72. printf("%d\n",-cost);
  73. }

23. 720B

大意: 给定一个边仙人掌, 边有颜色, 求删除一些边, 使它变为树, 且剩余边颜色种类数最大.

非环边直接从$S$连向对应颜色, $S$向每个环连一条$size-1$的边, 每个环再向每种颜色对应连边, 每种颜色连向$T$, 求最大流即为答案.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. #define pb push_back
  6. using namespace std;
  7.  
  8. const int N = 1e6+;
  9. int n, m, tot, dep[N], vis[N], u[N], v[N], w[N];
  10. struct _ {int to,w,id;} fa[N];
  11. vector<_> g[N];
  12.  
  13. namespace Dinic {
  14. const int S = N-, T = N-, INF = 0x3f3f3f3f;
  15. struct edge {
  16. int to,w,next;
  17. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  18. } e[N];
  19. int head[N], dep[N], vis[N], cur[N], cnt=;
  20. queue<int> Q;
  21. int bfs() {
  22. REP(i,,tot) dep[i]=INF,vis[i]=,cur[i]=head[i];
  23. dep[S]=INF,vis[S]=,cur[S]=head[S];
  24. dep[T]=INF,vis[T]=,cur[T]=head[T];
  25. dep[S]=,Q.push(S);
  26. while (Q.size()) {
  27. int u = Q.front(); Q.pop();
  28. for (int i=head[u]; i; i=e[i].next) {
  29. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  30. dep[e[i].to]=dep[u]+;
  31. Q.push(e[i].to);
  32. }
  33. }
  34. }
  35. return dep[T]!=INF;
  36. }
  37. int dfs(int x, int w) {
  38. if (x==T) return w;
  39. int used = ;
  40. for (int i=cur[x]; i; i=e[i].next) {
  41. cur[x] = i;
  42. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  43. int f = dfs(e[i].to,min(w-used,e[i].w));
  44. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  45. if (used==w) break;
  46. }
  47. }
  48. return used;
  49. }
  50. int dinic() {
  51. int ans = ;
  52. while (bfs()) ans+=dfs(S,INF);
  53. return ans;
  54. }
  55. void add(int u, int v, int w) {
  56. e[++cnt] = edge(v,w,head[u]);
  57. head[u] = cnt;
  58. e[++cnt] = edge(u,,head[v]);
  59. head[v] = cnt;
  60. }
  61. }
  62.  
  63. void get(int x, int y, _ e) {
  64. if (dep[x]<dep[y]) return;
  65. int sz = ;
  66. for (int t=x; t!=y; t=fa[t].to) ++sz;
  67. Dinic::add(Dinic::S,++tot,sz);
  68. Dinic::add(tot,e.w,), vis[e.id] = ;
  69. for (int t=x; t!=y; t=fa[t].to) {
  70. Dinic::add(tot,fa[t].w,), vis[fa[t].id] = ;
  71. }
  72. }
  73. void dfs(int x, int f) {
  74. dep[x]=dep[f]+;
  75. for (_ e:g[x]) if (e.to!=f) {
  76. int y = e.to;
  77. if (dep[y]) get(x,y,e);
  78. else fa[y]={x,e.w,e.id},dfs(y,x);
  79. }
  80. }
  81.  
  82. int main() {
  83. scanf("%d%d", &n, &m), tot = m;
  84. REP(i,,m) {
  85. scanf("%d%d%d", u+i, v+i, w+i);
  86. g[u[i]].pb({v[i],w[i],i}),g[v[i]].pb({u[i],w[i],i});
  87. Dinic::add(i,Dinic::T,);
  88. }
  89. dfs(,);
  90. REP(i,,m) if (!vis[i]) Dinic::add(Dinic::S,w[i],);
  91. printf("%d\n", Dinic::dinic());
  92. }

24. 723E

大意: 给定无向图, 无重边自环, 不保证连通, 要求把每条边定向, 使得入度等于出度的点最多.

25. 724E

大意: 给定有向图, 所有编号小的点与编号大的点间有一条有向边, 每条边流量均为$c$, 点$i$产出为$p_i$, 最多购入$s_i$, 求所有城市总购入量的最大值.

26. 727D

大意: $6$种衬衫, 每个人有两种或一种需求, 问是否能满足所有人的需求.

裸最大流

  1. #include <iostream>
  2. #include <sstream>
  3. #include <cstdio>
  4. #include <map>
  5. #include <queue>
  6. #define REP(i,a,n) for(int i=a;i<=n;++i)
  7. using namespace std;
  8.  
  9. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  10. int n;
  11. struct edge {
  12. int to,w,next;
  13. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  14. } e[N];
  15. int head[N], dep[N], vis[N], cur[N], cnt=;
  16. queue<int> Q;
  17. int bfs() {
  18. REP(i,,n) dep[i]=INF,vis[i]=,cur[i]=head[i];
  19. REP(i,S-,T) dep[i]=INF,vis[i]=,cur[i]=head[i];
  20. dep[S]=,Q.push(S);
  21. while (Q.size()) {
  22. int u = Q.front(); Q.pop();
  23. for (int i=head[u]; i; i=e[i].next) {
  24. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  25. dep[e[i].to]=dep[u]+;
  26. Q.push(e[i].to);
  27. }
  28. }
  29. }
  30. return dep[T]!=INF;
  31. }
  32. int dfs(int x, int w) {
  33. if (x==T) return w;
  34. int used = ;
  35. for (int i=cur[x]; i; i=e[i].next) {
  36. cur[x] = i;
  37. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  38. int f = dfs(e[i].to,min(w-used,e[i].w));
  39. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  40. if (used==w) break;
  41. }
  42. }
  43. return used;
  44. }
  45. int dinic() {
  46. int ans = ;
  47. while (bfs()) ans+=dfs(S,INF);
  48. return ans;
  49. }
  50. void add(int u, int v, int w) {
  51. e[++cnt] = edge(v,w,head[u]);
  52. head[u] = cnt;
  53. e[++cnt] = edge(u,,head[v]);
  54. head[v] = cnt;
  55. }
  56.  
  57. map<string,int> s;
  58. string val[N];
  59. int now = S;
  60.  
  61. int ID(string x) {
  62. if (s.count(x)) return s[x];
  63. val[now-] = x;
  64. return s[x] = --now;
  65. }
  66.  
  67. int main() {
  68. ID("S"),ID("M"),ID("L"),ID("XL"),ID("XXL"),ID("XXXL");
  69. REP(i,,) {
  70. int t;
  71. scanf("%d", &t);
  72. if (t) add(S-i,T,t);
  73. }
  74. scanf("%d", &n);
  75. REP(i,,n) {
  76. string t;
  77. cin>>t;
  78. for (auto &c:t) if (c==',') c=' ';
  79. stringstream ss(t);
  80. while (ss>>t) add(i,ID(t),);
  81. add(S,i,);
  82. }
  83. if (dinic()!=n) return puts("NO"),;
  84. puts("YES");
  85. REP(i,,n) {
  86. for (int j=head[i]; j; j=e[j].next) {
  87. if (!e[j].w) cout<<val[e[j].to]<<endl;
  88. }
  89. }
  90. }

27. 730I

大意: $n$个人, 选出$p$个人的编程组, $s$个人的运动组, 每个组价值为编程能力和或运动能力和, 求总能力和的最大值.

裸费用流. 数据范围比较大, 试了一下EK+spfa还是可过, 也可以用堆模拟费用流.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. using namespace std;
  6.  
  7. const int N = 1e6+, INF = 0x3f3f3f3f, S = N-, T = N-;
  8. int n, p, s, flow, cost;
  9. struct edge {
  10. int to,w,v,next;
  11. edge(int to=,int w=,int v=,int next=):to(to),w(w),v(v),next(next){}
  12. } e[N];
  13. int head[N], dep[N], vis[N], cur[N], f[N], cnt=;
  14. int pre[N],pre2[N];
  15. vector<int> g[N];
  16. queue<int> Q;
  17. int spfa() {
  18. REP(i,,n) f[i]=dep[i]=INF,vis[i]=;
  19. REP(i,S-,T) f[i]=dep[i]=INF,vis[i]=;
  20. dep[S]=,Q.push(S);
  21. while (Q.size()) {
  22. int u = Q.front(); Q.pop();
  23. vis[u] = ;
  24. for (int i=head[u]; i; i=e[i].next) {
  25. if (dep[e[i].to]>dep[u]+e[i].v&&e[i].w) {
  26. dep[e[i].to]=dep[u]+e[i].v;
  27. pre[e[i].to]=u,pre2[e[i].to]=i;
  28. f[e[i].to]=min(f[u],e[i].w);
  29. if (!vis[e[i].to]) {
  30. vis[e[i].to]=;
  31. Q.push(e[i].to);
  32. }
  33. }
  34. }
  35. }
  36. return dep[T]!=INF;
  37. }
  38. void EK(){
  39. while(spfa()) {
  40. int w = f[T];
  41. for (int u=T; u!=S; u=pre[u]) {
  42. e[pre2[u]].w-=w;
  43. e[pre2[u]^].w+=w;
  44. }
  45. flow += w, cost += w*dep[T];
  46. }
  47. }
  48. void add(int u, int v, int w, int k) {
  49. e[++cnt] = edge(v,w,k,head[u]);
  50. head[u] = cnt;
  51. e[++cnt] = edge(u,,-k,head[v]);
  52. head[v] = cnt;
  53. }
  54.  
  55. int main() {
  56. scanf("%d%d%d", &n, &p, &s);
  57. REP(i,,n) {
  58. int t;
  59. scanf("%d", &t);
  60. add(S,i,,);
  61. add(i,S-,,-t);
  62. }
  63. REP(i,,n) {
  64. int t;
  65. scanf("%d", &t);
  66. add(i,S-,,-t);
  67. }
  68. add(S-,T,p,),add(S-,T,s,);
  69. EK();
  70. REP(i,,n) {
  71. for (int j(head[i]); j; j=e[j].next) {
  72. if (!e[j].w) g[e[j].to].push_back(i);
  73. }
  74. }
  75. printf("%d\n", -cost);
  76. for (int i:g[S-]) printf("%d ",i);puts("");
  77. for (int i:g[S-]) printf("%d ",i);puts("");
  78. }

28. 736E

29. 739E

大意: $n$只精灵, $a$个普通球, $b$个高级球, 第$i$只精灵用普通球成功率$u_i$, 高级球$v_i$, 每只精灵同一种球最多用一次, 可以同时使用两种球, 求获得精灵期望最大值.

裸费用流, 同时扔两种球概率会减少$u_iv_i$, 从源点连一条流量$1$费用$0$, 和流量$1$费用$u_iv_i$的边即可, 这样一个点流量为$2$时, 费用一定会减去, 否则一定不会.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. using namespace std;
  6.  
  7. const int N = 1e6+, INF = 0x3f3f3f3f;
  8. const int X = N-, Y = N-, S = N-, T = N-;
  9. const double eps = 1e-;
  10. int n, a, b, flow;
  11. double cost, u[N], v[N], dep[N];
  12. struct edge {
  13. int to,w;
  14. double v;
  15. int next;
  16. edge(int to=,int w=,double v=,int next=):to(to),w(w),v(v),next(next){}
  17. } e[N];
  18. int head[N], vis[N], cur[N], f[N], cnt=;
  19. int pre[N],pre2[N],x[N],y[N];
  20. vector<int> g[N];
  21. queue<int> Q;
  22. int spfa() {
  23. REP(i,,n) f[i]=dep[i]=INF,vis[i]=;
  24. REP(i,N-,N-) f[i]=dep[i]=INF,vis[i]=;
  25. dep[S]=,Q.push(S);
  26. while (Q.size()) {
  27. int p = Q.front(); Q.pop();
  28. vis[p] = ;
  29. for (int i=head[p]; i; i=e[i].next) if (e[i].w) {
  30. double dis = dep[p]+e[i].v;
  31. if (dep[e[i].to]>dis+eps) {
  32. dep[e[i].to]=dis;
  33. pre[e[i].to]=p,pre2[e[i].to]=i;
  34. f[e[i].to]=min(f[p],e[i].w);
  35. if (!vis[e[i].to]) {
  36. vis[e[i].to]=;
  37. Q.push(e[i].to);
  38. }
  39. }
  40. }
  41. }
  42. return dep[T]!=INF;
  43. }
  44. void EK(){
  45. while(spfa()) {
  46. int w = f[T];
  47. for (int u=T; u!=S; u=pre[u]) {
  48. e[pre2[u]].w-=w;
  49. e[pre2[u]^].w+=w;
  50. }
  51. flow += w, cost += w*dep[T];
  52. }
  53. }
  54. void add(int u, int v, int w, double k) {
  55. e[++cnt] = edge(v,w,k,head[u]);
  56. head[u] = cnt;
  57. e[++cnt] = edge(u,,-k,head[v]);
  58. head[v] = cnt;
  59. }
  60.  
  61. int main() {
  62. scanf("%d%d%d", &n, &a, &b);
  63. REP(i,,n) scanf("%lf", u+i);
  64. REP(i,,n) scanf("%lf", v+i);
  65. REP(i,,n) {
  66. add(S,i,,);
  67. add(S,i,,u[i]*v[i]);
  68. add(i,X,,-u[i]);
  69. add(i,Y,,-v[i]);
  70. }
  71. add(X,T,a,),add(Y,T,b,);
  72. EK();
  73. printf("%.5lf\n", -cost);
  74. }

30. 786E

大意: 给定树, 给定$m$个人行走路线, 要求要么每个人自带一条狗, 要么路线上每条边都放一条狗, 求最少要多少只狗.

31. 793G

大意: $n*n$棋盘, 每行每列只能有一个棋子, 有$q$个矩形区域不能放棋子, 求最多放多少棋子

32. 802C

大意: 书架容量为$k$, 有$n$种书, 第$i$种$c_i$元, $n$个人按顺序来借书, 借完立刻还回, 第$i$个人要第$a_i$种, 若此时书架无$a_i$, 则要花费$c_{a_i}$元买书, 若书架满了, 则要扔掉一本. 求最少花费.

费用流好题, 开$2n$个点, $S$向$i$连一条费用$c_{a_i}$的边, 表示第$i$天新买一本书, $i$向$i+n$连费用$0$的边, 表示当天借完直接扔掉, $i+n$向$T$连费用$0$的边, 表示借书. $i$向$i+1$连容量$k-1$的边, 表示前一天最多向后一天保留$k-1$本书, 假设$a_i$的上次出现位置为$lst_{a_i}$, $i-1$向$lst_{a_i}+n$连费用$-c_{a_i}$的边, 表示撤销掉第$lst_{a_i}$的扔书操作, 使该书一直保留到$i-1$天. 最后跑一次最小费用最大流即为答案.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #define REP(i,a,n) for(int i=a;i<=n;++i)
  5. using namespace std;
  6.  
  7. const int N = 1e6+, INF = 0x3f3f3f3f, S = N-, T = N-;
  8. int n, k, flow, cost, a[N], c[N], lst[N];
  9. struct edge {
  10. int to,w,v,next;
  11. edge(int to=,int w=,int v=,int next=):to(to),w(w),v(v),next(next){}
  12. } e[N];
  13. int head[N], dep[N], vis[N], cur[N], f[N], cnt=;
  14. int pre[N],pre2[N];
  15. queue<int> Q;
  16. int spfa() {
  17. REP(i,,n) f[i]=dep[i]=INF,vis[i]=;
  18. f[S]=dep[S]=f[T]=dep[T]=INF;
  19. dep[S]=,Q.push(S);
  20. while (Q.size()) {
  21. int u = Q.front(); Q.pop();
  22. vis[u] = ;
  23. for (int i=head[u]; i; i=e[i].next) {
  24. if (dep[e[i].to]>dep[u]+e[i].v&&e[i].w) {
  25. dep[e[i].to]=dep[u]+e[i].v;
  26. pre[e[i].to]=u,pre2[e[i].to]=i;
  27. f[e[i].to]=min(f[u],e[i].w);
  28. if (!vis[e[i].to]) {
  29. vis[e[i].to]=;
  30. Q.push(e[i].to);
  31. }
  32. }
  33. }
  34. }
  35. return dep[T]!=INF;
  36. }
  37. void EK(){
  38. while(spfa()) {
  39. int w = f[T];
  40. for (int u=T; u!=S; u=pre[u]) {
  41. e[pre2[u]].w-=w;
  42. e[pre2[u]^].w+=w;
  43. }
  44. flow += w, cost += w*dep[T];
  45. }
  46. }
  47. void add(int u, int v, int w, int k) {
  48. e[++cnt] = edge(v,w,k,head[u]);
  49. head[u] = cnt;
  50. e[++cnt] = edge(u,,-k,head[v]);
  51. head[v] = cnt;
  52. }
  53.  
  54. int main() {
  55. scanf("%d%d", &n, &k);
  56. REP(i,,n) scanf("%d",a+i);
  57. REP(i,,n) scanf("%d",c+i);
  58. REP(i,,n) {
  59. add(S,i,,c[a[i]]);
  60. add(i,i+n,,);
  61. add(i+n,T,,);
  62. if (i!=) add(i-,i,k-,);
  63. if (lst[a[i]]) add(i-,lst[a[i]]+n,,-c[a[i]]);
  64. lst[a[i]] = i;
  65. }
  66. EK();
  67. printf("%d\n", cost);
  68. }

33. 802O

大意: $n$道题, 第$i$天可以花费$a_i$准备一道题, 花费$b_i$打印一道题, 每天最多准备一道, 最多打印一道, 准备的题可以留到以后打印, 求最少花费使得准备并打印$k$道题.

中等难度就是裸的费用流, 困难用堆模拟费用流.

34. 808F

大意: $n$张牌, 第$i$张能力$p_i$,魔法值$c_i$,等级$l_i$, 要求组一套牌, 使得任意两张牌的魔法值和不为素数, 且能力和不少于$k$, 求所需牌的等级最大值的最小值.

先二分答案, 素数可以按奇偶分开转化为二分图最大带权独立集, 然后最小割即可. 需要特判一下$1$, 多个$1$时只取$p$值最大的那个.

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <math.h>
  4. #include <cstdio>
  5. #include <queue>
  6. #define REP(i,a,n) for(int i=a;i<=n;++i)
  7. using namespace std;
  8.  
  9. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  10. int n, k, v[N];
  11. struct _ {int p,c,l;} a[N];
  12. struct edge {
  13. int to,w,next;
  14. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  15. } e[N];
  16. int head[N], dep[N], vis[N], cur[N], cnt=;
  17. queue<int> Q;
  18. int bfs() {
  19. REP(i,,n) dep[i]=INF,vis[i]=,cur[i]=head[i];
  20. dep[S]=INF,vis[S]=,cur[S]=head[S];
  21. dep[T]=INF,vis[T]=,cur[T]=head[T];
  22. dep[S]=,Q.push(S);
  23. while (Q.size()) {
  24. int u = Q.front(); Q.pop();
  25. for (int i=head[u]; i; i=e[i].next) {
  26. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  27. dep[e[i].to]=dep[u]+;
  28. Q.push(e[i].to);
  29. }
  30. }
  31. }
  32. return dep[T]!=INF;
  33. }
  34. int dfs(int x, int w) {
  35. if (x==T) return w;
  36. int used = ;
  37. for (int i=cur[x]; i; i=e[i].next) {
  38. cur[x] = i;
  39. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  40. int f = dfs(e[i].to,min(w-used,e[i].w));
  41. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  42. if (used==w) break;
  43. }
  44. }
  45. return used;
  46. }
  47. int dinic() {
  48. int ans = ;
  49. while (bfs()) ans+=dfs(S,INF);
  50. return ans;
  51. }
  52. void add(int u, int v, int w) {
  53. e[++cnt] = edge(v,w,head[u]);
  54. head[u] = cnt;
  55. e[++cnt] = edge(u,,head[v]);
  56. head[v] = cnt;
  57. }
  58.  
  59. void seive(int n) {
  60. int mx = sqrt(n+0.5);
  61. REP(i,,mx) if (!v[i]) {
  62. for (int j=i*i; j<=n; j+=i) v[j]=;
  63. }
  64. }
  65.  
  66. int chk(int n) {
  67. cnt = ;
  68. REP(i,,n) head[i] = ;
  69. REP(i,S,T) head[i] = ;
  70. REP(i,,n) if ((a[i].c&)&&a[i].c>) REP(j,,n) {
  71. if (!v[a[i].c+a[j].c]) add(i,j,INF);
  72. }
  73. REP(i,,n) if (a[i].c==) {
  74. REP(j,,n) if (i!=j) {
  75. if (a[j].c==) a[j].p=;
  76. else if (!v[+a[j].c]) add(i,j,INF);
  77. }
  78. }
  79. int sum = ;
  80. REP(i,,n) {
  81. sum += a[i].p;
  82. if (a[i].c&) add(S,i,a[i].p);
  83. else add(i,T,a[i].p);
  84. }
  85. return sum-dinic()>=k;
  86. }
  87.  
  88. int main() {
  89. seive(2e5);
  90. scanf("%d%d", &n, &k);
  91. REP(i,,n) scanf("%d%d%d",&a[i].p,&a[i].c,&a[i].l);
  92. sort(a+,a++n,[](_ a,_ b){return a.l<b.l||a.l==b.l&&a.p>b.p;});
  93. int l=,r=n,ans=-;
  94. while (l<=r) {
  95. int mid=(l+r)/;
  96. if (chk(mid)) ans=mid,r=mid-;
  97. else l=mid+;
  98. }
  99. if (ans==-) return puts("-1"),;
  100. printf("%d\n", a[ans].l);
  101. }

35. 813D & 818G

大意: 给定$n$元素序列, 求选出$4$个不相交的链, 链中相邻元素满足模7同余或差不超过$1$.

这题感觉建图没什么错但一直WA, 没调出来.

36. 843E

37. 848D

38. 847J

39. 852D

大意: 给定$V$节点$E$条边无向图, 给定$n$个队伍起始位置, 求最短多少时间$n$个队伍的结束位置不少于$k$.

先$floyd$求一下最短路, 然后二分答案看最大流是否超过$k$即可.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #include <string.h>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. using namespace std;
  7.  
  8. const int N = 1e6+, S = N-, T = N-, INF = 0x3f3f3f3f;
  9. int V,E,n,k,a[N];
  10. int dis[][];
  11. struct edge {
  12. int to,w,next;
  13. edge(int to=,int w=,int next=):to(to),w(w),next(next){}
  14. } e[N];
  15. int head[N], dep[N], vis[N], cur[N], cnt=;
  16. queue<int> Q;
  17. int bfs() {
  18. REP(i,,n+V) dep[i]=INF,vis[i]=,cur[i]=head[i];
  19. dep[S]=INF,vis[S]=,cur[S]=head[S];
  20. dep[T]=INF,vis[T]=,cur[T]=head[T];
  21. dep[S]=,Q.push(S);
  22. while (Q.size()) {
  23. int u = Q.front(); Q.pop();
  24. for (int i=head[u]; i; i=e[i].next) {
  25. if (dep[e[i].to]>dep[u]+&&e[i].w) {
  26. dep[e[i].to]=dep[u]+;
  27. Q.push(e[i].to);
  28. }
  29. }
  30. }
  31. return dep[T]!=INF;
  32. }
  33. int dfs(int x, int w) {
  34. if (x==T) return w;
  35. int used = ;
  36. for (int i=cur[x]; i; i=e[i].next) {
  37. cur[x] = i;
  38. if (dep[e[i].to]==dep[x]+&&e[i].w) {
  39. int f = dfs(e[i].to,min(w-used,e[i].w));
  40. if (f) used+=f,e[i].w-=f,e[i^].w+=f;
  41. if (used==w) break;
  42. }
  43. }
  44. return used;
  45. }
  46. int dinic() {
  47. int ans = ;
  48. while (bfs()) ans+=dfs(S,INF);
  49. return ans;
  50. }
  51. void add(int u, int v, int w) {
  52. e[++cnt] = edge(v,w,head[u]);
  53. head[u] = cnt;
  54. e[++cnt] = edge(u,,head[v]);
  55. head[v] = cnt;
  56. }
  57.  
  58. int chk(int x) {
  59. cnt = ;
  60. REP(i,,n+V) head[i] = ;
  61. REP(i,S,T) head[i] = ;
  62. REP(i,,n) REP(j,,V) {
  63. if (dis[a[i]][j]<=x) add(i,j+n,);
  64. }
  65. REP(i,,n) add(S,i,);
  66. REP(i,,V) add(i+n,T,);
  67. return dinic()>=k;
  68. }
  69.  
  70. int main() {
  71. scanf("%d%d%d%d", &V, &E, &n, &k);
  72. REP(i,,n) scanf("%d",a+i);
  73. memset(dis,0x3f,sizeof dis);
  74. REP(i,,V) dis[i][i]=;
  75. REP(i,,E) {
  76. int a,b,t;
  77. scanf("%d%d%d",&a,&b,&t);
  78. dis[a][b]=dis[b][a]=min(dis[a][b],t);
  79. }
  80. REP(k,,V)REP(i,,V)REP(j,,V) {
  81. dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
  82. }
  83. int l=,r=,ans=-;
  84. while (l<=r) {
  85. int mid=(l+r)/;
  86. if (chk(mid)) ans=mid,r=mid-;
  87. else l=mid+;
  88. }
  89. printf("%d\n", ans);
  90. }

40. 863F

大意: $n$元素序列, 每个元素取值范围$[1,n]$, 有$q$个限制$(t,l,r,x)$, 表示$[l,r]$内的元素$\le x$或$\ge x$, 定义$cnt_i$为元素$i$的出现次数, 求$\sum cnt_i^2$的最小值.

费用流水题, 贡献为平方可以拆成$n$条流量为$1$, 费用为$1,3,5,7...$的边.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #include <map>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. using namespace std;
  7. typedef pair<int,int> pii;
  8.  
  9. const int N = 1e6+, INF = 0x3f3f3f3f, S = N-, T = N-;
  10. int n, tot, q, flow, cost;
  11. int L[N], R[N];
  12. struct edge {
  13. int to,w,v,next;
  14. edge(int to=,int w=,int v=,int next=):to(to),w(w),v(v),next(next){}
  15. } e[N];
  16. int head[N], dep[N], vis[N], cur[N], f[N], cnt=;
  17. int pre[N],pre2[N];
  18. queue<int> Q;
  19. int spfa() {
  20. REP(i,,tot) f[i]=dep[i]=INF,vis[i]=;
  21. f[S]=dep[S]=f[T]=dep[T]=INF;
  22. dep[S]=,Q.push(S);
  23. while (Q.size()) {
  24. int u = Q.front(); Q.pop();
  25. vis[u] = ;
  26. for (int i=head[u]; i; i=e[i].next) {
  27. if (dep[e[i].to]>dep[u]+e[i].v&&e[i].w) {
  28. dep[e[i].to]=dep[u]+e[i].v;
  29. pre[e[i].to]=u,pre2[e[i].to]=i;
  30. f[e[i].to]=min(f[u],e[i].w);
  31. if (!vis[e[i].to]) {
  32. vis[e[i].to]=;
  33. Q.push(e[i].to);
  34. }
  35. }
  36. }
  37. }
  38. return dep[T]!=INF;
  39. }
  40. void EK(){
  41. while(spfa()) {
  42. int w = f[T];
  43. for (int u=T; u!=S; u=pre[u]) {
  44. e[pre2[u]].w-=w;
  45. e[pre2[u]^].w+=w;
  46. }
  47. flow += w, cost += w*dep[T];
  48. }
  49. }
  50. void add(int u, int v, int w, int k) {
  51. e[++cnt] = edge(v,w,k,head[u]);
  52. head[u] = cnt;
  53. e[++cnt] = edge(u,,-k,head[v]);
  54. head[v] = cnt;
  55. }
  56.  
  57. map<pii,int> mp;
  58. int ID(int x, int y) {
  59. if (mp.count(pii(x,y))) return mp[pii(x,y)];
  60. return mp[pii(x,y)] = ++tot;
  61. }
  62.  
  63. int main() {
  64. scanf("%d%d", &n, &q);
  65. REP(i,,n) L[i]=,R[i]=n;
  66. REP(i,,q) {
  67. int op,l,r,x;
  68. scanf("%d%d%d%d",&op,&l,&r,&x);
  69. if (op==) {
  70. REP(j,l,r) L[j]=max(L[j],x);
  71. }
  72. else {
  73. REP(j,l,r) R[j]=min(R[j],x);
  74. }
  75. }
  76. REP(i,,n) {
  77. if (L[i]>R[i]) return puts("-1"),;
  78. add(S,ID(n+,i),,);
  79. REP(j,L[i],R[i]) {
  80. add(ID(n+,i),ID(i,j),,);
  81. add(ID(i,j),ID(n+,j),,);
  82. }
  83. }
  84. REP(i,,n) REP(j,,n) add(ID(n+,i),T,,*j-);
  85. EK();
  86. printf("%d\n", cost);
  87. }

41. 884F

大意: 定义一个长为$n$的串$s$为反回文串, 当且仅当对于$1\le i\le n$有$s[i]!=s[n-i+1]$. 给定串$s$, 求将$s$重排为一个反回文串$t$, 对于$1\le i\le n$, 若$s[i]=t[i]$, 则得分$b[i]$, 求最大得分值.

挺不错的费用流题, 也可以贪心做.

统计一下每个字符的出现次数$c_i$, 从$S$向字符$x$连$c_x$. 每个位置$i$拆成$26$个点, 从字符$x$连向每个点, 若$s[i]=x$则加一个费用$-b_i$. 然后就是处理反回文的限制, 对于每对限制$(i,n-i+1)$, 再新开$26$个点, $i$和$n-i+1$分别向新开的点连容量$1$, 最后再开个点限制两边流量和为$2$即可. 这样建图的话实际上会导致一个错误: 每对限制$(i,n-i+1)$, 可能取了$i$两个, 而$n-i+1$没有取到. 但是思考一下很容易发现这样并不影响最终结果.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #include <map>
  5. #define REP(i,a,n) for(int i=a;i<=n;++i)
  6. using namespace std;
  7. typedef pair<int,int> pii;
  8. const int N = 1e6+, INF = 0x3f3f3f3f, S = N-, T = N-;
  9. int n, tot, flow, cost, b[N], c[N];
  10. char s[N];
  11. struct edge {
  12. int to,w,v,next;
  13. edge(int to=,int w=,int v=,int next=):to(to),w(w),v(v),next(next){}
  14. } e[N];
  15. int head[N], dep[N], vis[N], cur[N], f[N], cnt=;
  16. int pre[N],pre2[N];
  17. queue<int> Q;
  18. int spfa() {
  19. REP(i,,tot) f[i]=dep[i]=INF,vis[i]=;
  20. f[S]=dep[S]=f[T]=dep[T]=INF;
  21. dep[S]=,Q.push(S);
  22. while (Q.size()) {
  23. int u = Q.front(); Q.pop();
  24. vis[u] = ;
  25. for (int i=head[u]; i; i=e[i].next) {
  26. if (dep[e[i].to]>dep[u]+e[i].v&&e[i].w) {
  27. dep[e[i].to]=dep[u]+e[i].v;
  28. pre[e[i].to]=u,pre2[e[i].to]=i;
  29. f[e[i].to]=min(f[u],e[i].w);
  30. if (!vis[e[i].to]) {
  31. vis[e[i].to]=;
  32. Q.push(e[i].to);
  33. }
  34. }
  35. }
  36. }
  37. return dep[T]!=INF;
  38. }
  39. void EK(){
  40. while(spfa()) {
  41. int w = f[T];
  42. for (int u=T; u!=S; u=pre[u]) {
  43. e[pre2[u]].w-=w;
  44. e[pre2[u]^].w+=w;
  45. }
  46. flow += w, cost += w*dep[T];
  47. }
  48. }
  49. void add(int u, int v, int w, int k) {
  50. e[++cnt] = edge(v,w,k,head[u]);
  51. head[u] = cnt;
  52. e[++cnt] = edge(u,,-k,head[v]);
  53. head[v] = cnt;
  54. }
  55.  
  56. map<pii,int> mp;
  57. int ID(int x, int y) {
  58. if (mp.count(pii(x,y))) return mp[pii(x,y)];
  59. return mp[pii(x,y)] = ++tot;
  60. }
  61.  
  62. int main() {
  63. scanf("%d%s", &n, s+);
  64. REP(i,,n) ++c[s[i]];
  65. REP(i,,n) scanf("%d",b+i);
  66. REP(i,'a','z') add(S,ID(-,i),c[i],);
  67. REP(i,,n) REP(j,'a','z') {
  68. add(ID(-,j),ID(i,j),,s[i]==j?-b[i]:);
  69. }
  70. REP(i,,n/) {
  71. REP(j,'a','z') {
  72. add(ID(i,j),ID(i+n,j),,);
  73. add(ID(n-i+,j),ID(i+n,j),,);
  74. add(ID(i+n,j),ID(i,),,);
  75. }
  76. add(ID(i,),T,,);
  77. }
  78. EK();
  79. printf("%d\n", -cost);
  80. }

42. 903G

大意:两个n元素集合$A$, $B$, $A_i$与$A_{i+1}$连一条有向边, $B_i$与$B_{i+1}$连一条有向边, 给定$m$条从$A_i$连向$B_j$的有向边, 每次询问修改$A_x->A_{x+1}$的边权, 求$A_1$->$B_n$的最大流.

43. 925F

44. 965D

大意: 河宽$w$, 青蛙每步能跳不超过$l$, 有$w-1$块石头, 石头每踩一次就会消失, 求最大过河青蛙数.

45. 976F

大意: 给定二分图, 对于$k \in [0,minDegree]$, 输出最小$k$覆盖.

46. 1009G

47. 1016D

大意: 有一个$nm$矩阵, 给定每行每列异或和, 求是否存在. 若存在输出一个方案.

1045A

1054F

1061E

1070I

1107F

1119B

1139E

1146G

CF网络流练习的更多相关文章

  1. CF#366 704D Captain America 上下界网络流

    CF上的题,就不放链接了,打开太慢,直接上题面吧: 平面上有n个点, 第 i 个点的坐标为 ($X_i ,Y_i$), 你需要把每个点染成红色或者蓝色, 染成红色的花费为 r , 染成蓝色的花费为 b ...

  2. HDU 4888 (网络流)

    Poroblem Redraw Beautiful Drawings (HDU4888) 题目大意 一个n行m列的矩形,只能填0~k的数字. 给定各行各列的数字和,判定有无合法的方案数.一解给出方案, ...

  3. POJ1459 最大网络流

    问题: POJ1459 涉及内容:最大网络流 分析: 本题问题看似非常复杂,实际上可以转化为单源点单汇点的最大网络流问题. 1)因为电量只在发电站产生,故增加源点S,构建从S到每个发电站的有向边,边的 ...

  4. HLG 2163 方格取数 (最大网络流)

    题目链接:  m=ProblemSet&a=showProblem&problem_id=2163">点击打开链接 Description : 给你一个n*n的格子的棋 ...

  5. 洛谷P2402 奶牛隐藏(网络流,二分答案,Floyd)

    洛谷题目传送门 了解网络流和dinic算法请点这里(感谢SYCstudio) 题目 题目背景 这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你.(奶牛 ...

  6. 【CF802C】Heidi and Library(网络流)

    [CF802C]Heidi and Library(网络流) 题面 CF 洛谷 题解 前面两个Easy和Medium都是什么鬼玩意啊.... 不难发现如果这天的要求就是第\(a_i\)种书的话,那么\ ...

  7. BZOJ2673 [Wf2011]Chips Challenge 费用流 zkw费用流 网络流

    https://darkbzoj.cf/problem/2673 有一个芯片,芯片上有N*N(1≤N≤40)个插槽,可以在里面装零件. 有些插槽不能装零件,有些插槽必须装零件,剩下的插槽随意. 要求装 ...

  8. BZOJ2055 80人环游世界 网络流 费用流 有源汇有上下界的费用流

    https://darkbzoj.cf/problem/2055 https://blog.csdn.net/Clove_unique/article/details/54864211 ←对有上下界费 ...

  9. 【算法】【网络流24题】巨坑待填(成功TJ,有时间再填)

    ------------------------------------------------------------------------------------ 17/24 --------- ...

随机推荐

  1. docker实战之通过nginx镜像来部署静态页

    本章我们主要讲解如何通过docker构建一个nginx容器,这里我们以部署一个静态html为素材来进行演示. 首先我们通过[docker search nginx]命令来查找Docker Hub上的n ...

  2. Flutter移动电商实战 --(38)路由_Fluro中Handler编写方法

    在main.dart中初始化Fluro 编写handler 在lib下新建routers文件夹,表示里面要很多路由相关的文件 我们声明一个Handler,在里面handlerFunc固定的两个参数 重 ...

  3. treeview所有节点递归解法及注意!!!!!!!!!!!!!!!!!

    好吧 我把所有之前写的都删了,只为这一句话“所有变量切记小心在递归函数内部初始化”,包括:布尔,变量i,等等.至于为什么....递归就是调用自己,你初始化以后的变量,等再次调用的时候又回来了 bool ...

  4. UML期末复习题——2.8:UML Design Class Diagram(DCD)

    第八题:设计类图 重要概念: 1. 类图(Class Diagram): 类图是面向对象系统建模中最常用和最重要的图,是定义其它图的基础.类图主要是用来显示系统中的类.接口以及它们之间的静态结构和关系 ...

  5. 2.5 Go语言基础之map

    Go语言中提供的映射关系容器为map, Go中内置类型,其内部使用散列表(hash)实现,为引用类型. 无序键值对(key-value)集合,通过key(类似索引)快速检索数据 必须初始化才能使用. ...

  6. android之Framework问题总结:

    移动开发知识体系总章(Java基础.Android.Flutter) Android Handler消息机制 . Android中为什么主线程不会因为Looper.loop里的无限循环ANR? 1.1 ...

  7. SpringBoot: 10.整合mybatis(转)

    需求:通过使用 SpringBoot+SpringMVC+MyBatis 整合实现一个对数据库中的 t_user 表的 CRUD 的操作 1.创建maven项目,添加项目所需依赖 <!--spr ...

  8. 【ARM-Linux开发】ARM7 ARM9 ARM Cortex M3 M4 有什么区别

    ARM7 ARM9 ARM Cortex M3 M4 区别 arm7 arm9 可以类比386和奔腾, 不同代,arm9相比arm7指令集和性能都有所增强,arm7和arm9都有带mmu和无mmu的版 ...

  9. RestHighLevelClient 之 Scroll

    ES中默认最大查询结果为10000,大于10000时查不出结果,报错超过最大值,如把 from调到大于10000. 针对这个问题,有两种解决办法. 第一种,修改 max_result_window 很 ...

  10. OpenCV.概念(读书笔记)

    ZC:学习OpenCV.pdf 1.多通道矩阵(学习OpenCV.pdf) 1.1.在学习opencv的时候看到多通道矩阵这一概率,恳求大神告诉我一下什么意思_百度知道.html(https://zh ...