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;
}
posted @ 2024-02-27 18:12  ChiFAN鸭  阅读(6)  评论(0编辑  收藏  举报