Description
Kiana最近喜欢到一家非常美味的寿司餐厅用餐。每天晚上,这家餐厅都会按顺序提供n种寿司,第i种寿司有一个代号ai和美味度di,i,不同种类的寿司有可能使用相同的代号。每种寿司的份数都是无限的,Kiana也可以无限次取寿司来吃,但每种寿司每次只能取一份,且每次取走的寿司必须是按餐厅提供寿司的顺序连续的一段,即Kiana可以一次取走第1,2种寿司各一份,也可以一次取走第2,3种寿司各一份,但不可以一次取走第1,3种寿司。由于餐厅提供的寿司种类繁多,而不同种类的寿司之间相互会有影响:三文鱼寿司和鱿鱼寿司一起吃或许会很棒,但和水果寿司一起吃就可能会肚子痛。因此,Kiana定义了一个综合美味度di,j(i<j),表示在一次取的寿司中,如果包含了餐厅提供的从第i份到第j份的所有寿司,吃掉这次取的所有寿司后将获得的额外美味度。由于取寿司需要花费一些时间,所以我们认为分两次取来的寿司之间相互不会影响。注意在吃一次取的寿司时,不止一个综合美味度会被累加,比如若Kiana一次取走了第1,2,3种寿司各一份,除了d1,3以外,d1,2,d2,3也会被累加进总美味度中。神奇的是,Kiana的美食评判标准是有记忆性的,无论是单种寿司的美味度,还是多种寿司组合起来的综合美味度,在计入Kiana的总美味度时都只会被累加一次。比如,若Kiana某一次取走了第1,2种寿司各一份,另一次取走了第2,3种寿司各一份,那么这两次取寿司的总美味度为d1,1+d2,2+d3,3+d1,2+d2,3,其中d2,2只会计算一次。奇怪的是,这家寿司餐厅的收费标准很不同寻常。具体来说,如果Kiana一共吃过了c(c>0)种代号为x的寿司,则她需要为这些寿司付出mx^2+cx元钱,其中m是餐厅给出的一个常数。现在Kiana想知道,在这家餐厅吃寿司,自己能获得的总美味度(包括所有吃掉的单种寿司的美味度和所有被累加的综合美味度)减去花费的总钱数的最大值是多少。由于她不会算,所以希望由你告诉她
Solution
可以说是最大权闭合子图的裸题了吧……
对于每个
d
i
,
j
d_{i,j}
di,j(
i
<
j
i<j
i<j),权值为
d
i
,
j
d_{i,j}
di,j,选了它就必须选
d
i
+
1
,
j
、
d
i
,
j
−
1
d_{i+1,j}、d_{i,j-1}
di+1,j、di,j−1,对于每种代号新建一个点,权值为
m
x
2
mx^2
mx2,每个
d
i
,
i
d_{i,i}
di,i连向它对应的代号的点,权值为
d
i
,
i
−
a
i
d_{i,i}-a_i
di,i−ai。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=110;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,a[Maxn],d[Maxn][Maxn],st,ed;
struct Edge{int y,d,next;}e[Maxn*Maxn<<4];
int last[Maxn*Maxn+2000],len=1;
void ins(int x,int y,int d)
{
int t=++len;
e[t].y=y;e[t].d=d;e[t].next=last[x];last[x]=t;
}
void addedge(int x,int y,int d){ins(x,y,d),ins(y,x,0);}
int h[Maxn*Maxn+2000];
bool bfs()
{
memset(h,0,sizeof(h));h[st]=1;
queue<int>q;q.push(st);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(e[i].d>0&&!h[y])h[y]=h[x]+1,q.push(y);
}
}
return h[ed];
}
int dfs(int x,int f)
{
if(x==ed)return f;
int s=0,t;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(e[i].d>0&&h[y]==h[x]+1&&s<f)
{
t=dfs(y,min(e[i].d,f-s));
s+=t;e[i^1].d+=t;e[i].d-=t;
}
}
if(!s)h[x]=0;
return s;
}
int P(int x,int y){return(x-1)*n+y;}
bool mark[1010];
int main()
{
int ans=0;
n=read(),m=read();st=n*n+1001,ed=n*n+1002;
for(int i=1;i<=n;i++)mark[a[i]=read()]=true;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
d[i][j]=read();
if(i<j)addedge(P(i,j),P(i+1,j),inf),addedge(P(i,j),P(i,j-1),inf);
int v=d[i][j];
if(i==j)
{
v-=a[i];
addedge(P(i,j),a[i]+n*n,inf);
}
if(v>0)ans+=v,addedge(st,P(i,j),v);
else addedge(P(i,j),ed,-v);
}
for(int i=1;i<=1000;i++)if(mark[i])addedge(i+n*n,ed,m*i*i);
while(bfs())ans-=dfs(st,inf);
printf("%d",ans);
}