BZOJ 4873: [Shoi2017]寿司餐厅 最大权闭合图
比较好想的建模题.
显然,如果选 $[l,r]$ 的话只要强制选 $[l,r-1]$ 与 $[l+1,r]$ 就行了.
然后 $m=0$ 的话直接在 $[i,i]$ 上扣掉编号大小就行.
如果 $m=1$,就套路的新建一个点,然后练一下限制的编号就行了.
code:
#include <bits/stdc++.h> #define N 20006 #define M 103 #define I(s) freopen(s".in","r",stdin) #define O(s) freopen(s".out","w",stdout) #define setIO(s) I(s) using namespace std; const int inf=2000000001; namespace net { struct Edge { int u,v; int c; Edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){} }; queue<int>q; vector<Edge>edges; vector<int>G[N]; int vv[N],vis[N],d[N],bo[N],s,t; void add(int u,int v,int c) { edges.push_back(Edge(u,v,c)); edges.push_back(Edge(v,u,0)); int o=edges.size(); G[u].push_back(o-2); G[v].push_back(o-1); } int dfs(int x,int cur) { if(x==t) return cur; int an=0,flow=0; for(int i=vv[x];i<G[x].size();++i,++vv[x]) { Edge e=edges[G[x][i]]; if(e.c>0&&d[e.v]==d[x]+1) { an=dfs(e.v,min(cur,e.c)); if(an) { cur-=an; flow+=an; edges[G[x][i]].c-=an; edges[G[x][i]^1].c+=an; if(!cur) break; } } } return flow; } int bfs() { memset(vis,0,sizeof(vis)); d[s]=0; vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<G[u].size();++i) { if(edges[G[u][i]].c>0) { int v=edges[G[u][i]].v; if(!vis[v]) { vis[v]=1; d[v]=d[u]+1; q.push(v); } } } } return vis[t]; } int maxflow() { int re=0; while(bfs()) { memset(vv,0,sizeof(vv)); re+=(int)dfs(s,inf); } return re; } }; int a[N],val[M][M],id[M][M]; vector<int>G[N]; int main() { // setIO("input"); int n,m,tim=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) { scanf("%d",&a[i]); G[a[i]].push_back(i); } for(int i=1;i<=n;++i) { for(int j=i;j<=n;++j) scanf("%d",&val[i][j]),id[i][j]=++tim; } for(int i=1;i<=n;++i) val[i][i]-=a[i]; int s=0,t=n*n+n+2,SUM=0; net::s=s,net::t=t; for(int i=1;i<=n;++i) { for(int j=i;j<=n;++j) { if(j>i) { net::add(id[i][j],id[i+1][j],inf); net::add(id[i][j],id[i][j-1],inf); } if(val[i][j]>0) { SUM+=val[i][j]; net::add(s,id[i][j],val[i][j]); } else { net::add(id[i][j],t,-val[i][j]); } } } for(int i=0;i<=1000;++i) { if(G[i].size()) { ++tim; net::add(tim,t,m*i*i); for(int j=0;j<G[i].size();++j) { int y=G[i][j]; net::add(id[y][y],tim,inf); } } } printf("%d\n",SUM-net::maxflow()); return 0; }