1. 程式人生 > >BZOJ4873 Shoi2017壽司餐廳(最小割)

BZOJ4873 Shoi2017壽司餐廳(最小割)

  選擇了某個區間就必須選擇其所有子區間,容易想到這是一個最大權閉合子圖的模型。考慮將區間按長度分層,相鄰層按包含關係連邊,區間[i,j]的權值即di,j,其中最後一層表示長度為1的區間的同時也表示壽司本身,所以其權值減去x。這樣建出原圖,再用最大權閉合子圖的方法重建就行了。於是m=0的情況就解決了。給最後一層的點連向壽司代號,m=1也就做完了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include
<algorithm> using namespace std; #define ll long long #define N 110 #define M 6789 #define S 0 #define T 6666 #define inf 1000000010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0
?n:gcd(m,n%m);} 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 n,m,a[N],v[N][N],id[N][N],id2[1010],p[M],t=-1,cnt,ans; int d[M],cur[M],q[M];
struct data{int to,nxt,cap,flow; }edge[M<<3]; void addedge(int x,int y,int z) { t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=0,p[x]=t; t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=0,edge[t].flow=0,p[y]=t; } bool bfs() { memset(d,255,sizeof(d));d[S]=0; int head=0,tail=1;q[1]=S; do { int x=q[++head]; for (int i=p[x];~i;i=edge[i].nxt) if (d[edge[i].to]==-1&&edge[i].flow<edge[i].cap) { q[++tail]=edge[i].to; d[edge[i].to]=d[x]+1; } }while (head<tail); return ~d[T]; } int work(int k,int f) { if (k==T) return f; int used=0; for (int i=cur[k];~i;i=edge[i].nxt) if (d[k]+1==d[edge[i].to]) { int w=work(edge[i].to,min(f-used,edge[i].cap-edge[i].flow)); edge[i].flow+=w,edge[i^1].flow-=w; if (edge[i].flow<edge[i].cap) cur[k]=i; used+=w;if (used==f) return f; } if (used==0) d[k]=-1; return used; } void dinic() { while (bfs()) { memcpy(cur,p,sizeof(p)); ans-=work(S,inf); } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4873.in","r",stdin); freopen("bzoj4873.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=n;i++) for (int j=i;j<=n;j++) v[i][j]=read(); memset(p,255,sizeof(p)); for (int k=n;k>=1;k--) for (int i=1;i<=n-k+1;i++) { int j=i+k-1; id[i][j]=++cnt; if (i>1) addedge(id[i-1][j],id[i][j],inf); if (j<n) addedge(id[i][j+1],id[i][j],inf); int x=v[i][j];if (k==1) x-=a[i]; if (x>0) ans+=x,addedge(S,id[i][j],x); else addedge(id[i][j],T,-x); } if (m==1) for (int i=1;i<=n;i++) { if (!id2[a[i]]) id2[a[i]]=++cnt,addedge(id2[a[i]],T,a[i]*a[i]); addedge(id[i][i],id2[a[i]],inf); } dinic(); cout<<ans; return 0; }