选择了某个区间就必须选择其所有子区间,容易想到这是一个最大权闭合子图的模型。考虑将区间按长度分层,相邻层按包含关系连边,区间[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 "; #else const char LL[]="%lld "; #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; }