抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

原题链接

nn 个二次函数,第 ii 个形如fi(x)=aix2+bix+cif_i(x)=a_ix^2+b_ix+c_i

你的总收益是i=1nfi(xi)\sum_{i=1}^nf_i(x_i),但是有几个限制:

  1. xix_i​[li,ri][l_i,r_i]​ 中的一个整数
  2. 还给了 mm 条额外的限制,每条形如u v d,表示的是xuxv+dx_u\leq x_v+d

求最大的总收益。

n50;m100;ai10;bi,ci1000;100liri100;di200n\le 50; m\le 100; |a_i|\le 10;|b_i|,|c_i|\le1000;-100\le l_i\le r_i\le 100;|d_i|\le 200[1]

题解

感觉和刚刚做过一场模拟赛的一道题很类似……

考虑网络流,对每个函数都建立 [li,ri][l_i,r_i]​ 的点,点 (i,j)(i,j)​ 表示函数 fif_i​xi=jx_i=j​时的点。

我们考虑最小损失。设一个极大值 limlim(大于所有的fi(x)f_i(x)),将也就是要求limfi(x)lim-f_i(x) 的最小值。

我们从点 (i,j)(i,j) 向点 (i,j+1)(i,j+1)(如果j=rij=r_i 那就是超汇 TT)流limfi(j)lim - f_i(j),从超源SS 向点 (i,li)(i,l_i)\infty

大概就是这样一张图:

如果这些函数的取值互补干涉,那么 n×lim最小割n\times lim-\text{最小割}就是答案。

我们考虑如何加入这些限制。

如果现在有限制 xuxv+dx_u\le x_v+d,也就是xvxudx_v\ge x_u-d。如果我们割了xux_u 这条边,在 vv 这条链上我们只能割 xudx_u-d 以后的边。那就不妨从 uu 这条表上所有的 xxvv这条边上所有的 xdx-d 连一条 \infty​ 的边。

如果割绿色的那两条边:

很开心地测一下样例,炸了……

我们来看这种情形(对样例 1 略有改动):

1
2
3
4
5
6
7
2 2
0 1 0
0 1 1
2 3
1 2
1 2 0
2 1 0

建出来的图大概是长这样的:

最小割是选 (1,3)T(1,3)\to T(2,3)T(2,3)\to T

但显然 (1,3)T(1,3)\to T​ 是不能选的。因为由 x1x2x_1\le x_2​x2x1x_2\le x_1​可知x1=x2x_1=x_2​

于是我们只得再建一个 (i,ri+1)(i,r_i+1) 点,(i,ri)(i,ri+1)(i,r_i)\to (i,r_i+1)fi(ri)f_i(r_i)(i,ri+1)T(i,r_i+1)\to T\infty

这样就完美了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const LL maxn = 10005;
const LL maxm = 5000005;
const LL inf = 0x3f3f3f3f3f3f3f3f;
const LL lim = 1000000000000;

struct Edge
{
LL to, nxt, cap;
} e[maxm << 1];

LL first[maxn], first_bak[maxn];

inline void add_edge(LL from, LL to, LL cap)
{
static LL cnt = -1;
e[++cnt].nxt = first[from];
first[from] = cnt;
e[cnt].to = to;
e[cnt].cap = cap;
e[++cnt].nxt = first[to];
first[to] = cnt;
e[cnt].to = from;
e[cnt].cap = 0;
}

LL n, m, S, T;

LL bh[105][205];
LL a[maxn], b[maxn], c[maxn];
LL ll[maxn];
LL rr[maxn];
LL dep[maxn];

inline LL getans(LL I, LL x)
{
return a[I] * x * x + b[I] * x + c[I];
}

inline bool bfs()
{
memset(dep, 0x3f, sizeof(dep));
queue<LL> q;
q.push(S);
dep[S] = 0;
for(int i = S; i <= T; ++i)
first[i] = first_bak[i];
while(!q.empty())
{
LL now = q.front();
q.pop();
for(int i = first[now]; ~i; i = e[i].nxt)
{
LL to = e[i].to;
if(dep[to] >= inf && e[i].cap > 0)
{
dep[to] = dep[now] + 1;
q.push(to);
}
}
}
return dep[T] < inf;
}

inline LL dfs(LL now, LL lim)
{
if(!lim || now == T)
return lim;
LL flow = 0;
for(int i = first[now]; ~i; i = e[i].nxt)
{
first[now] = i;
register LL to = e[i].to, f;
if(dep[to] == dep[now] + 1 && (f = dfs(to, min(lim, e[i].cap))) > 0)
{
lim -= f;
flow += f;
e[i].cap -= f;
e[i ^ 1].cap += f;
if(lim <= 0)
break;
}
}
return flow;
}

inline LL dinic()
{
LL flow = 0;
while(bfs())
flow += dfs(S, inf);
return flow;
}

int main()
{
memset(first, 0xff, sizeof(first));
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= n; ++i)
scanf("%lld%lld%lld", &a[i], &b[i], &c[i]);
for(int i = 1; i <= n; ++i)
{
scanf("%lld%lld", &ll[i], &rr[i]);
add_edge(S, T + 1, inf);
for(LL j = ll[i] + 100; j <= rr[i] + 101; ++j)
{
bh[i][j] = ++T;
if(j != ll[i] + 100)
add_edge(bh[i][j - 1], bh[i][j], lim - getans(i, j - 1 - 100));
}
}
T++;
for(LL i = 1; i <= n; ++i)
add_edge(bh[i][rr[i] + 101], T, inf);
for(int i = 1, u, v, d; i <= m; ++i)
{
scanf("%d%d%d", &u, &v, &d);
for(int j = ll[u]; j <= rr[u] + 1; ++j)
if(ll[v] <= j - d && j - d <= rr[v] + 1)
add_edge(bh[u][j + 100], bh[v][j - d + 100], inf);
}
for(int i = S; i <= T; ++i)
first_bak[i] = first[i];
printf("%lld\n", n * lim - dinic());
return 0;
}

  1. 翻译来自luogu,略有改动。 ↩︎

评论