[六省联考2017]寿司餐厅

Posted by Dispwnl on April 26, 2019

题目

题解

题目要求的就是$\sum d-(mx^2+cx)$的最大值

看到这玩意我就想到了最大权闭合子图,直接建边$((i,i),T,a_i),(a_i,T,{a_i}^2)$,然后分值的正负每个区间连$S/T$,区间之间连一下$\inf$边即可

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
# define LL long long
using namespace std;
const int MAX=1e5+5,N=105,inf=1e9;
struct p{
	int x,y,d;
}c[MAX];
int n,m,num=1,cnt,T,ans;
int h[MAX],H[MAX],use[MAX],d[MAX],a[MAX],qu[MAX];
int id[N][N];
int read()
{
	int x=0,fl=1;
	char ch=getchar();
	for(;!isdigit(ch);fl=(ch=='-')?-1:1,ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x*fl;
}
void add(int x,int y,int d)
{
	c[++num]=(p){h[x],y,d},h[x]=num;
	c[++num]=(p){h[y],x,0},h[y]=num;
}
bool bfs()
{
	memset(d,0,sizeof(d));
	int hl=1,tl=d[0]=1;
	while(hl<=tl)
	{
		int tt=qu[hl++];
		for(int i=h[tt],y;i;i=c[i].x)
		  if(c[i].d&&!d[y=c[i].y])
		  {
		  	d[y]=d[tt]+1,qu[++tl]=y;
		  	if(y==T) return 1;
		  }
	}
	return 0;
}
int dfs(int x=0,int dix=inf)
{
	if(x==T||!dix) return dix;
	int sum=0;
	for(int &i=H[x],dis,y;i;i=c[i].x)
	  if(d[y=c[i].y]==d[x]+1&&c[i].d)
	  {
	  	dis=dfs(y,min(dix,c[i].d));
	  	if(dis)
	  	{
	  		c[i].d-=dis,c[i^1].d+=dis,sum+=dis,dix-=dis;
	  		if(!dix) break;
		}
	  }
	if(!sum) d[x]=-2;
	return sum;
}
int Dinic()
{
	int tot=0,D;
	while(bfs())
	{
		memcpy(H,h,sizeof(h));
		while(D=dfs()) tot+=D;
	}
	return tot;
}
int main()
{
	n=read(),m=read(),T=n*n+n+1;
	for(int i=1;i<=n;++i)
	  {
	  	a[i]=read();
	  	if(!use[a[i]]&&m) add(use[a[i]]=++cnt,T,a[i]*a[i]);
	  	for(int j=i;j<=n;++j)
	  	  id[i][j]=++cnt;
		add(id[i][i],T,a[i]),add(id[i][i],use[a[i]],inf);
	  }
	for(int i=1;i<=n;++i)
	  for(int j=i,x;j<=n;++j)
	    {
	    	x=read();
	    	if(x>0) add(0,id[i][j],x),ans+=x;
	    	else add(id[i][j],T,-x);
	    	if(i!=j) add(id[i][j],id[i+1][j],inf),add(id[i][j],id[i][j-1],inf);
		}
	return printf("%d",ans-Dinic()),0;
}