[六省联考 2017] 寿司餐厅 题解
题目描述
Kiana 最近喜欢到一家非常美味的寿司餐厅用餐。
每天晚上,这家餐厅都会按顺序提供 \(n\) 种寿司,第 \(i\) 种寿司有一个代号 \(a_i\) 和美味度 \(d_{i, i}\),不同种类的寿司有可能使用相同的代号。每种寿司的份数都是无限的,Kiana 也可以无限次取寿司来吃,但每种寿司每次只能取一份,且每次取走的寿司必须是按餐厅提供寿司的顺序连续的一段,即 Kiana 可以一次取走第 \(1, 2\) 种寿司各一份,也可以一次取走第 \(2, 3\) 种寿司各一份,但不可以一次取走第 \(1, 3\) 种寿司。
由于餐厅提供的寿司种类繁多,而不同种类的寿司之间相互会有影响:三文鱼寿司和鱿鱼寿司一起吃或许会很棒,但和水果寿司一起吃就可能会肚子痛。因此,Kiana 定义了一个综合美味度 \(d_{i, j} \ (i < j)\),表示在一次取的寿司中,如果包含了餐厅提供的从第 \(i\) 份到第 \(j\) 份的所有寿司,吃掉这次取的所有寿司后将获得的额外美味度。由于取寿司需要花费一些时间,所以我们认为分两次取来的寿司之间相互不会影响。注意在吃一次取的寿司时,不止一个综合美味度会被累加,比如若 Kiana 一次取走了第 \(1, 2, 3\) 种寿司各一份,除了 \(d_{1, 3}\) 以外,\(d_{1, 2}, d_{2, 3}\) 也会被累加进总美味度中。
神奇的是,Kiana 的美食评判标准是有记忆性的,无论是单种寿司的美味度,还是多种寿司组合起来的综合美味度,在计入 Kiana 的总美味度时都只会被累加一次。比如,若 Kiana 某一次取走了第 \(1, 2\) 种寿司各一份,另一次取走了第 \(2, 3\) 种寿司各一份,那么这两次取寿司的总美味度为 \(d_{1, 1} + d_{2, 2} + d_{3, 3} + d_{1, 2} + d_{2, 3}\),其中 \(d_{2, 2}\) 只会计算一次。
奇怪的是,这家寿司餐厅的收费标准很不同寻常。具体来说,如果 Kiana 一共吃过了 \(c \ (c > 0)\) 种代号为 \(x\) 的寿司,则她需要为这些寿司付出 \(mx^2 + cx\) 元钱,其中 \(m\) 是餐厅给出的一个常数。
现在 Kiana 想知道,在这家餐厅吃寿司,自己能获得的总美味度(包括所有吃掉的单种寿司的美味度和所有被累加的综合美味度)减去花费的总钱数的最大值是多少。由于她不会算,所以希望由你告诉她。
输入格式
第一行包含两个正整数 \(n, m\),分别表示这家餐厅提供的寿司总数和计算寿司价格中使用的常数。
第二行包含 \(n\) 个正整数,其中第 \(k\) 个数 \(a_k\) 表示第 \(k\) 份寿司的代号。
接下来 \(n\) 行,第 \(i\) 行包含 \(n - i + 1\) 个整数,其中第 \(j\) 个数 \(d_{i, i+j-1}\) 表示吃掉寿司能获得的相应的美味度,具体含义见问题描述。
输出格式
输出共一行包含一个正整数,表示 Kiana 能获得的总美味度减去花费的总钱数的最大值。
样例 #1
样例输入 #1
3 1
2 3 2
5 -10 15
-10 15
15
样例输出 #1
12
样例 #2
样例输入 #2
5 0
1 4 1 3 4
50 99 8 -39 30
68 27 -75 -32
70 24 72
-10 81
-95
样例输出 #2
381
样例 #3
样例输入 #3
10 1
5 5 4 4 1 2 5 1 5 3
83 91 72 29 22 -5 57 -14 -36 -3
-11 34 45 96 32 73 -1 0 29
-48 68 44 -5 96 66 17 74
88 47 69 -9 2 25 -49
86 -9 -77 62 -10 -30
2 40 95 -74 46
49 -52 2 -51
-55 50 -44
72 22
-68
样例输出 #3
1223
提示
样例解释 1
在这组样例中,餐厅一共提供了 \(3\) 份寿司,它们的代号依次为 \(a_1 = 2, a_2 = 3, a_3 = 2\),计算价格时的常数 \(m = 1\)。
在保证每次取寿司都能获得新的美味度的前提下,Kiana 一共有 \(14\) 种不同的吃寿司方案。以下列出其中几种:
- Kiana 一个寿司也不吃,这样她获得的总美味度和花费的总钱数都是 \(0\),两者相减也是 \(0\);
- Kiana 只取 \(1\) 次寿司,且只取第 \(1\) 个寿司,即她取寿司的情况为 \(\{[1, 1]\}\),这样获得的总美味度为 \(5\),花费的总钱数为 \(1 \times 2^2 + 1 \times 2 = 6\),两者相减为 \(-1\);
- Kiana 取 \(2\) 次寿司,第一次取第 \(1, 2\) 个寿司,第二次取第 \(2, 3\) 个寿司,即她取寿司的情况为 \(\{[1, 2], [2, 3]\}\),这样获得的总美味度为 \(5 + (-10) + 15 + (-10) + 15 = 15\),花费的总钱数为 \((1 \times 2^2 + 2 \times 2) + (1 \times 3^2 + 1 \times 3) = 20\),两者相减为 \(-5\);
- Kiana 取 \(2\) 次寿司,第一次取第 \(1\) 个寿司,第二次取第 \(3\) 个寿司,即她取寿司的情况为 \(\{[1, 1], [3, 3]\}\),这样获得的总美味度为 \(5 + 15 = 20\),花费的总钱数为 \(1 \times 2^2 + 2 \times 2 = 8\),两者相减为 \(12\)。
在 \(14\) 种方案中,惟一的最优方案是列出的最后一种方案,这时她获得的总美味度减去花费的总钱数的值最大为 \(12\)。
数据范围
对于所有数据,保证 \(-500 \leq d_{i, j} \leq 500\)。
数据的一些特殊约定如下表:
| Case # | \(n\) | \(a_i\) | \(m\) | 附加限制 |
|---|---|---|---|---|
| 1 | \(\leq 2\) | \(\leq 30\) | \(= 0\) | - |
| 2 | \(\leq 2\) | \(\leq 30\) | \(= 1\) | - |
| 3 | \(\leq 3\) | \(\leq 30\) | \(= 0\) | - |
| 4 | \(\leq 3\) | \(\leq 30\) | \(= 1\) | - |
| 5 | \(\leq 5\) | \(\leq 30\) | \(= 0\) | - |
| 6 | \(\leq 5\) | \(\leq 30\) | \(= 1\) | - |
| 7 | \(\leq 10\) | \(\leq 30\) | \(= 0\) | 所有的 \(a_i\) 相同 |
| 8 | \(\leq 10\) | \(\leq 30\) | \(= 1\) | - |
| 9 | \(\leq 15\) | \(\leq 30\) | \(= 0\) | 所有的 \(a_i\) 相同 |
| 10 | \(\leq 15\) | \(\leq 30\) | \(= 1\) | - |
| 11 | \(\leq 30\) | \(\leq 1000\) | \(= 0\) | 所有的 \(a_i\) 相同 |
| 12 | \(\leq 30\) | \(\leq 30\) | \(= 0\) | 所有的 \(a_i\) 相同 |
| 13 | \(\leq 30\) | \(\leq 1000\) | \(= 0\) | - |
| 14 | \(\leq 30\) | \(\leq 1000\) | \(= 1\) | - |
| 15 | \(\leq 50\) | \(\leq 1000\) | \(= 0\) | 所有的 \(a_i\) 相同 |
| 16 | \(\leq 50\) | \(\leq 30\) | \(= 0\) | 所有的 \(a_i\) 相同 |
| 17 | \(\leq 50\) | \(\leq 1000\) | \(= 0\) | - |
| 18 | \(\leq 50\) | \(\leq 1000\) | \(= 1\) | - |
| 19 | \(\leq 100\) | \(\leq 1000\) | \(= 0\) | - |
| 20 | \(\leq 100\) | \(\leq 1000\) | \(= 1\) | - |
SOLUTION
前置芝士——最大权闭合子图模型
有 \(n\) 个物品,第 \(i\) 个物品的价值为 \(w_i\)(可以为负),存在若干形如选 \(i\) 必须选 \(j\) 的限制。
最小割。
令超源 \(S\) 所在的集合为选择的物品集合,超汇 \(T\) 所在的集合为不选择的物品的集合
显然对于一个物品 \(i\) ,要么属于 \(S\) ,要么属于 \(T\)。
对于价值为正的物品 \(i\),从 \(S\) 向 \(i\) 连边,边权为 \(w_i\)
表示不选择 \(i\) 会损失 \(wi\) 的收益。
对于价值为负或零的物品 \(i\),从 \(i\) 向 \(T\) 连边,边权为 \(−wi\) (显然 \(−wi>0\) )
表示选择了 \(i\) 要付出 \(−wi\) 的代价,即损失 \(−wi\) 的收益
对于选择 \(i\) 必选 \(j\) 的限制,由 \(i\) 向 \(j\) 连边,表示 \(j\) 必须属于 \(i\) 所在的集合
设最小割为 \(ans\),则最后所选择物品的收益最大值为 \(sum−ans\)
令 \(sum=∑_{w_i>0}w_i\)
其实最小割求的是最终不选的
对于\(value>0\)的割掉意味着不选,损失\(value\)
对于\(value<0\)的割掉意味着要选,损失\(-value\)
所以就是选出最小损失,然后\(答案=sum-ans\)
回归本题
然后我们考虑将题目解读成网络流最大权闭合子图
收费:
如果一共吃过了\(c\) 种代号为\(x\) 的寿司,则需要为这些寿司付出\(mx^2+cx\)元钱
也就是每次吃一次代号为\(x\)的寿司,就会付\(x\)元钱
且但凡吃过代号为\(x\)的寿司,就会付\(mx^2\)元钱--------------\((1)\)
又由于最终求的是总美味度减去花费的总钱数的最大值
所以我们想到了将代号\(x\)的单独辟成一个点,每一段\([i,j]\)也是一个点\(id[i][j]\)
-
对于\([i,i]\),\(id[i][i]\to T,flow=w[i][i]-a[i]\),\(id[i][j]\to idx[a[i]]\)
第二个解释:就是\((1)\)那个地方,确保有代号\(x\)的寿司出现时,会有\(mx^2\)的花费
-
对于\([i,j](j≠i)\),\(id[i][j]\to id[i+1][j]\),\(id[i][j]\to id[i][j-1]\)
就是对应题目的
注意在吃一次取的寿司时,不止一个综合美味度会被累加 -
对于代号\(x\),\(idx[x]\to T,flow=mx^2\)
注意\(s\to id[i][j]\)的连边还是按照最大权闭合子图的模型连
这样我们就可以用最小割解决这个问题了
CODE
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=5e6+2,M=1e3+2,INF=1e18;
ll n,m,a[M],b[M],v[M][M],id[M][M],pos[M],t[M],S,T,tot,ans,sum;
ll cnt,hd[N],d[N];
struct node{ll to,nxt,w;}e[N];
void add(ll x,ll y,ll w){
e[++cnt]={y,hd[x],w};
hd[x]=cnt;
}
bool bfs(){
queue<ll>q;
memset(d,0,sizeof(d));
q.push(S),d[S]=1;
while(!q.empty()){
ll x=q.front();q.pop();
for(ll i=hd[x];~i;i=e[i].nxt){
ll y=e[i].to,w=e[i].w;
if(w&&!d[y]){
d[y]=d[x]+1;
if(y==T)return 1;
q.push(y);
}
}
}
return 0;
}
ll dinic(ll x,ll flow){
if(x==T)return flow;
ll k,r=flow;
for(ll i=hd[x];~i&&r;i=e[i].nxt){
ll y=e[i].to,w=e[i].w;
if(!w||d[y]!=d[x]+1)continue;
k=dinic(y,min(r,w));
if(!k)d[y]=0;
e[i].w-=k;
e[i^1].w+=k;
r-=k;
if(!r)return flow;
}
return flow-r;
}
int main(){
scanf("%lld%lld",&n,&m);
memset(hd,-1,sizeof(hd));
cnt=1;
S=0;
ll mx=0;
for(ll i=1;i<=n;i++){
scanf("%lld",&a[i]);
mx=max(mx,a[i]);
for(ll j=i;j<=n;j++){
id[i][j]=++tot;
}
}
T=mx+tot+1;
for(ll i=1;i<=mx;i++){
b[i]=tot+i;
add(b[i],T,i*i*m),add(T,b[i],0);
}
for(ll i=1;i<=n;i++){
for(ll j=i;j<=n;j++){
scanf("%lld",&v[i][j]);
if(i==j)v[i][i]-=a[i];
if(v[i][j]>0){
sum+=v[i][j];
add(S,id[i][j],v[i][j]),add(id[i][j],S,0);
}else{
add(id[i][j],T,-v[i][j]),add(T,id[i][j],0);
}
if(i==j){
add(id[i][j],b[a[i]],INF),add(b[a[i]],id[i][j],0);
}else{
add(id[i][j],id[i+1][j],INF),add(id[i+1][j],id[i][j],0);
add(id[i][j],id[i][j-1],INF),add(id[i][j-1],id[i][j],0);
}
}
}
while(bfs()){
ans+=dinic(S,INF);
}
printf("%lld",sum-ans);
return 0;
}
完结撒花❀
★,°:.☆( ̄▽ ̄)/$:.°★ 。

浙公网安备 33010602011771号