P3749 [六省联考 2017] 寿司餐厅
由于 \(m = 1\) 的情况难以 dp,且每个物品只有选或不选,考虑最小割,设与 \(S\) 连通表示选,否则表示不选。边有以下几种:
首先考虑 \(d _ {i, j}\) 的贡献。但原问题是最大化,这里需要转化成减去最小代价。如果 \(d _ {i, j} > 0\),则把答案先加上 \(d _ {i, j}\),再在 \(S\) 和 \((i ,j)\) 连 \(d _ {i, j}\) 的边,割掉表示不选有 \(d _ {i, j}\) 的代价;如果 \(d _ {i, j} < 0\),则在 \((i, j)\) 和 \(T\) 连 \(-d _ {i, j}\) 的边,割掉表示选有 \(-d _ {i, j}\) 的代价。
然后是 \(a _ i\),选一种寿司会有 \(a _ i\) 的代价,在 \((i, i)\) 和 \(T\) 连 \(a _ i\) 的边。
每一种标号的贡献则在 \(x\) 和 \(T\) 连 \(mx ^ 2\) 的边,表示选有 \(mx ^ 2\) 的代价。
接下来是一些限制。首先若选了 \((i, j)\) 则所有 \([i', j'] \subset [i, j]\) 的 \((i', j')\) 都必须选,所以在 \((i, j)\) 和 \((i', j')\) 连 \(+\infty\) 的边,表示不能被割,这样就保证 \((i, j) \in S\) 时一定有 \((i', j') \in S\)。
但这样边数比较多,你考虑子区间一定是原区间从左边和右边删掉若干个数后形成,所以连边 \((i, j) \rightarrow (i + 1, j)\),\((i, j) \rightarrow (i, j - 1)\),边权都是 \(+\infty\),就能保证从 \((i, j)\) 能走到任意一个子区间。
还有就是选了一个物品就一定要选 \(a _ i\) 这个标号,同理在 \((i, i)\) 和 \(a _ i\) 连 \(+\infty\) 的边。
然后就可以跑最大流了,答案就是所有 \(d _ {i, j} > 0\) 的 \(d _ {i, j}\) 的和减去最大流。
点数和边数都是 \(\text O (n ^ 2)\)。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10005
#define M 40005
using namespace std;
const int V=1000;
int n,op,ans,a[105],b[105][105];
struct netflow {
const int inf=0x3f3f3f3f;
int S,T;
int tot=1,head[N],nxt[M],ver[M],e[M];
int cnt,id1[1005],id2[105][105];
int d[N],now[N];
int lt,rt,q[N];
void insert_(int x,int y,int z) {
ver[++tot]=y,e[tot]=z,nxt[tot]=head[x],head[x]=tot;
}
void insert(int x,int y,int z) {
insert_(x,y,z),insert_(y,x,0);
}
bool bfs() {
memset(d,0,sizeof(d)),lt=1,rt=0;
d[S]=1,now[S]=head[S],q[++rt]=S;
while(lt<=rt) {
int x=q[lt++];
for(int i=head[x];i;i=nxt[i]) {
int y=ver[i],z=e[i];
if(!d[y]&&z) {
d[y]=d[x]+1,now[y]=head[y];
if(y==T) return 1;
q[++rt]=y;
}
}
}
return 0;
}
int dinic(int x,int flow) {
if(x==T) return flow;
int rest=flow;
for(int i=now[x];i&&rest;i=nxt[i]) {
int y=ver[i],z=e[i]; now[x]=i;
if(d[y]<=d[x]||!z) continue;
int k=dinic(y,min(rest,z));
if(!k) d[y]--;
else rest-=k,e[i]-=k,e[i^1]+=k;
}
return flow-rest;
}
void build() {
S=++cnt,T=++cnt;
for(int i=1;i<=V;i++) {
if(op) id1[i]=++cnt,insert(cnt,T,i*i);
}
for(int i=n;i;i--) {
id2[i][i]=++cnt,insert(cnt,T,a[i]);
if(op) insert(cnt,id1[a[i]],inf);
for(int j=i+1;j<=n;j++) {
id2[i][j]=++cnt;
insert(cnt,id2[i+1][j],inf),insert(cnt,id2[i][j-1],inf);
}
for(int j=i;j<=n;j++) {
if(b[i][j]>0) insert(S,id2[i][j],b[i][j]);
if(b[i][j]<0) insert(id2[i][j],T,-b[i][j]);
}
}
}
int maxflow() {
int res=0,flow;
while(bfs()) while(flow=dinic(S,inf)) res+=flow;
return res;
}
} t1;
int main() {
scanf("%d%d",&n,&op);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) scanf("%d",&b[i][j]),ans+=max(b[i][j],0);
t1.build();
printf("%d\n",ans-t1.maxflow());
return 0;
}

浙公网安备 33010602011771号