【最大权闭合子图】bzoj4873: [Shoi2017]寿司餐厅

为什么跑得这么慢

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想知道,在这家餐厅吃寿司,自己能获得的总美
味度(包括所有吃掉的单种寿司的美味度和所有被累加的综合美味度)减去花费的总钱数的最大值是多少。由于她
不会算,所以希望由你告诉她

Input

第一行包含两个正整数n,m,分别表示这家餐厅提供的寿司总数和计算寿司价格中使用的常数。
第二行包含n个正整数,其中第k个数ak表示第k份寿司的代号。
接下来n行,第i行包含n-i+1个整数,其中第j个数di,i+j-1表示吃掉寿司能
获得的相应的美味度,具体含义见问题描述。
N<=100,Ai<=1000

Output

输出共一行包含一个正整数,表示Kiana能获得的总美味度减去花费的总钱数的最大值。


题目分析

以后这样一类的点权最大化问题可以向最大权闭合子图的方向考虑。

对于区间$d_{i,j}$向$d_{i+1,j},d_{i,j-1}$连边;再对于每一种$a_i$建个点,从$d_{i,i}$向$a_i$连边。

剩下的就是一样的模型了。

 1 #include<bits/stdc++.h>
 2 const int maxn = 103;
 3 const int maxm = 100035;
 4 const int maxNode = 50035;
 5 const int INF = 2e9;
 6 
 7 struct Edge
 8 {
 9     int u,v,f,c;
10     Edge(int a=0, int b=0, int c=0, int d=0):u(a),v(b),f(c),c(d) {}
11 }edges[maxm];
12 int edgeTot,head[maxNode],nxt[maxm],lv[maxNode];
13 int n,k,ans,S,T;
14 int a[maxn],d[maxn][maxn],id[maxn][maxn],ida[1035],idt;
15 
16 int read()
17 {
18     char ch = getchar();
19     int num = 0, fl = 1;
20     for (; !isdigit(ch); ch=getchar())
21         if (ch=='-') fl = -1;
22     for (; isdigit(ch); ch=getchar())
23         num = (num<<1)+(num<<3)+ch-48;
24     return num*fl;
25 }
26 void addedge(int u, int v, int c)
27 {
28     edges[edgeTot] = Edge(u, v, 0, c), nxt[edgeTot] = head[u], head[u] = edgeTot, ++edgeTot;
29     edges[edgeTot] = Edge(v, u, 0, 0), nxt[edgeTot] = head[v], head[v] = edgeTot, ++edgeTot;
30 }
31 bool buildLevel()
32 {
33     memset(lv, 0, sizeof lv);
34     std::queue<int> q;
35     lv[S] = 1, q.push(S);
36     for (int tmp; q.size(); )
37     {
38         tmp = q.front(), q.pop();
39         for (int i=head[tmp]; i!=-1; i=nxt[i])
40         {
41             int v = edges[i].v;
42             if (!lv[v]&&edges[i].f < edges[i].c){
43                 lv[v] = lv[tmp]+1, q.push(v);
44                 if (v==T) return true;
45             }
46         }
47     }
48     return false;
49 }
50 int fndPath(int x, int lim)
51 {
52     int sum = 0;
53     if (x==T||!lim) return lim;
54     for (int i=head[x]; i!=-1&&sum < lim; i=nxt[i])
55     {
56         int v = edges[i].v, val;
57         if (lv[v]==lv[x]+1&&edges[i].f < edges[i].c){
58             if ((val = fndPath(v, std::min(lim-sum, edges[i].c-edges[i].f))))
59                 edges[i].f += val, edges[i^1].f -= val, sum += val;
60             else lv[v] = -1;
61         }
62     }
63     return sum;
64 }
65 int dinic()
66 {
67     int ret = 0, val;
68     while (buildLevel())
69         if ((val = fndPath(S, INF))) ret += val;
70     return ret;
71 }
72 int main()
73 {
74     memset(head, -1, sizeof head);
75     n = read(), k = read(), S = 0, T = idt = 1;
76     for (int i=1; i<=n; i++) a[i] = read();
77     for (int i=1; i<=n; i++)
78         for (int j=i; j<=n; j++)
79         {
80             d[i][j] = read(), id[i][j] = ++idt;
81             if (d[i][j] > 0) addedge(S, id[i][j], d[i][j]), ans += d[i][j];
82             else addedge(id[i][j], T, -d[i][j]);
83         }
84     for (int i=1; i<=n; i++)
85     {
86         addedge(id[i][i], T, a[i]);
87         if (!ida[a[i]]) ida[a[i]] = ++idt, addedge(idt, T, k*a[i]*a[i]);
88         addedge(id[i][i], ida[a[i]], INF);
89     }
90     for (int i=1; i<=n; i++)
91         for (int j=i+1; j<=n; j++)
92             addedge(id[i][j], id[i][j-1], INF), 
93             addedge(id[i][j], id[i+1][j], INF);
94     printf("%d\n",ans-dinic());
95     return 0;
96 }

以上两个标红的地方一改,从$848ms$->$106ms$.

 

END

posted @ 2019-03-06 18:57  AntiQuality  阅读(123)  评论(0编辑  收藏  举报