P3749 题解
既然是求最大值而且有收益有代价,所以考虑建立一个最大权封闭子图模型。
收益
正的美味值是收益,所以假若 \(d_{i,j} \geq 0\) 则建边 \((s,pos_{i,j},d_{i,j})\)。
代价
负的美味值是代价,所以假若 \(d_{i,j} < 0\) 则建边 \((pos_{i,j},t,-d_{i,j})\)。
吃某种代号的寿司会收钱,吃没吃和吃多少分开计算,种类 \(x\) 建边 \((x,t,m \times x^2)\)。寿司 \(i\) 建边 \((pos_{i,i},t,a_i)\)。
依赖关系
吃了区间 \([l,r]\) 内的寿司也一定吃了被这个区间所包含的区间内的寿司,所以建边 \((pos_{i,j},pos_{i+1,j})\) 与 \((pos_{i,j},pos_{i,j-1})\)。
吃没吃某一种寿司也是一种依赖关系,所有 \(a_i = x\) 的 \(i\) 建边\((pos_{i,i},x,inf)\)。
那么建完边之后跑一遍最大流即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+114;
const int inf = INT_MAX;
int maxflow,tot=1;
int s,t,hd[maxn],road[maxn],dis[maxn];
struct edge{
int next,to,w;
}e[maxn*2];
void add(int u,int v,int w){
e[++tot].to=v;
e[tot].w=w;
e[tot].next=hd[u];
hd[u]=tot;
e[++tot].to=u;
e[tot].w=0;
e[tot].next=hd[v];
hd[v]=tot;
}
bool bfs(bool flag){
memset(dis,0,sizeof(dis));
dis[s]=1;
queue<int>Q;
Q.push(s);
while(!Q.empty())
{
int u=Q.front();
Q.pop();
road[u]=hd[u];
for(int i=hd[u];i;i=e[i].next)
{
int v=e[i].to;
if(!dis[v]&&e[i].w)
{
dis[v]=dis[u]+1;
Q.push(v);
}
}
}
return dis[t]!=0;
}
int dinic(int now,int res){
if(now==t)
return res;
int tp=res;
for(int i=road[now];i;i=e[i].next)
{
int v=e[i].to;road[now]=i;
if(dis[v]==dis[now]+1&&e[i].w)
{
int k=min(e[i].w,tp);
int del=dinic(v,k);
e[i].w-=del;
e[i^1].w+=del;
tp-=del;
if(!tp)
break;
}
}
return res-tp;
}
int a[maxn],n,m,d[1001][1001],pos[1001][1001],cnt,sum;
map<int,int> vis;
map<int,int> type;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
s=++cnt;
t=++cnt;
for(int i=1;i<=n;i++){
cin>>a[i];
if(vis[a[i]]==false){
vis[a[i]]=true;
type[a[i]]=++cnt;
add(type[a[i]],t,m*a[i]*a[i]);
}
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
cin>>d[i][j];
pos[i][j]=++cnt;
}
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
if(d[i][j]>=0) sum+=d[i][j],add(s,pos[i][j],d[i][j]);
else add(pos[i][j],t,-d[i][j]);
if(i!=j){
add(pos[i][j],pos[i+1][j],inf);
add(pos[i][j],pos[i][j-1],inf);
}
}
}
for(int i=1;i<=n;i++){
add(pos[i][i],type[a[i]],inf);
add(pos[i][i],t,a[i]);
}
while(bfs(true)==true) maxflow+=dinic(s,inf);
cout<<sum-maxflow;
return 0;
}