题目描述
Shy 有 n 个发电站。每个发电站有一个 level(可正可负的整数),i 号发电站的 level要在 l[i],r[i]之间(包含),Level x 会带来 fi(x)的发电量。
Shy 还有 m 个限制。限制是这样的形式,x[u]≤x[v]+d,表示 u 的 level 小于等于 v 的level 加 d(d 是整数)。
请问最大发电量是多少。
输入格式
第一行两个整数 n,m 表示发电站的数目和限制的数目;
接下来 n 行,每行三个整数ai,bi,ciai,bi,ci 表示 fifi,fi(x)=ai∗x∗x+bi∗x+cifi(x)=ai∗x∗x+bi∗x+ci;
接下来 n 行每行两个整数 l[i],r[i];
接下来 m 行,每行三个整数 u,v,d,表示 x[u]≤x[v]+dx[u]≤x[v]+d。
输出格式
一个正整数表示答案。
输入样例
5 8
1 -8 20
2 -4 0
-1 10 -10
0 1 0
0 -1 1
1 9
1 4
0 10
3 11
7 9
2 1 3
1 2 3
2 3 3
3 2 3
3 4 3
4 3 3
4 5 3
5 4 3
输出样例
46
提示
数据规模
对于 30%的数据,1≤n≤3;
对于 100%的数据,
1≤n≤50,0≤m≤100,|ai|≤10,|bi|≤1000,|ci|≤1000,−100≤|li|≤|ri|≤100,1≤u,v≤n,u≠v,|di|≤2001≤n≤50,0≤m≤100,|ai|≤10,|bi|≤1000,|ci|≤1000,−100≤|li|≤|ri|≤100,1≤u,v≤n,u≠v,|di|≤200。
解题分析:
发现此题数据范围只有50,容易想到这是一道网络流的题目。 显然一组解是使得每个发电站发电量最大的和, 并且每个发电站都能发电, 那么我们可以用最小割模型来处理每个发电站都能发电的情况。
设f(x)f(x)表示某个发电站在取到x时能发电的量。倘若没有限制条件,我们设某个发电站的可行区间为[i,j][i,j],那么我们就可以将在可行区间内的取值视为j−i+1j−i+1点, 将每个点之间的流量定为f(x)f(x), 连成一条链, 将一头一尾分别与源点和汇点连接。这样建出的图跑最小割就会保证每条链上都会取到一个值。
然而我们要的是最大割。实际上我们取−f(x)−f(x)再加上一个很大的值保证其为正数即可。
现在考虑加上限制。x[u]−d≤x[v]x[u]−d≤x[v], 因为我们是最小割模型, 所以要保证uu所在链的取值减去一个常数要小于所在链的取值, 直接将差值为d的两条链上的点连一条流量为infinf的边即可。 这样就保证了在最小割的情况下, 要割掉uu所在链上的m点, 就要保证所在链上的大于等于m+dm+d位置的点一定也要被割(否则还是联通的)。 剩下的就只有打板啦…
PS:此题一定要加当前弧优化, 否则会T 20-30 分…
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <queue>
#define R register
#define gc getchar()
#define IN inline
#define W while
#define trans 19260817
#define inf 99999999
#define MX 1000005
#define st 0
#define ed 500000
static bool fu;
template <class T>
IN void in (T &x)
{
fu = false; x = 0; R char c = gc;
W (!isdigit(c))
{if(c == '-') fu = true; c = gc;}
W (isdigit(c))
{x = (x << 1) + (x << 3) + c - 48, c = gc;}
if(fu) x = -x;
}
struct Dat
{
int a, b, c;
}dat[55];
int from[55], head[MX], lef[55], rig[55], cnt = -1, dot, num, cpy[MX];
struct Edge
{
int to, flow, nex;
}edge[MX];
IN int cal(const int &typ, const int &pos)
{ return -(dat[typ].a * pos * pos + dat[typ].b * pos + dat[typ].c) + trans;}
IN void addedge(const int &from, const int &to, const int &len)
{
edge[++cnt] = (Edge){to, len, head[from]};
head[from] = cnt;
}
namespace Dinic
{
int layer[MX];
std::queue <int> q;
IN bool BFS()
{
R int now;
memset(layer, 0, sizeof(layer));
layer[st] = 1;
q.push(st);
W (!q.empty())
{
now = q.front();
q.pop();
for (R int i = head[now]; ~i; i = edge[i].nex)
{
if(layer[edge[i].to] || !edge[i].flow) continue;
layer[edge[i].to] = layer[now] + 1;
q.push(edge[i].to);
}
}
return layer[ed];
}
int DFS(int now, int value)
{
if(now == ed || !value) return value;
int ret = 0, tmp;
for (R int &i = head[now]; ~i; i = edge[i].nex)
{
if(!edge[i].flow || layer[edge[i].to] != layer[now] + 1) continue;
tmp = DFS(edge[i].to, std::min(value - ret, edge[i].flow));
if(!tmp) continue;
edge[i].flow -= tmp;
edge[i ^ 1].flow += tmp;
ret += tmp;
if(value == ret) return value;
}
return ret;
}
long long Dinic_init()
{
long long ans = 0;
std::memcpy(cpy, head, 500001);
W (BFS())
{
ans += DFS(st, inf);
std::memcpy(head, cpy, 500001);
} ans = ans - dot * trans;
ans = -ans;
return ans;
}
}
using namespace Dinic;
int main(void)
{
memset(head, -1, sizeof(head));
int jcq, ncq, a, b, c;
in(dot), in(num);
for (R int i = 1; i <= dot; ++i) in(dat[i].a), in(dat[i].b), in(dat[i].c);
for (R int i = 1; i <= dot; ++i) in(lef[i]), in(rig[i]);
for (R int i = 1; i <= dot; ++i)
{
jcq = i * 605;//两个点间预留600空间, 存它的取值范围内的点, 避免重复。
addedge(st, jcq + lef[i], inf), addedge(jcq + rig[i] + 1, ed, inf);
addedge(jcq + lef[i], st, 0), addedge(ed, jcq + rig[i] + 1, 0);
for (R int j = lef[i]; j <= rig[i]; ++j)
addedge(jcq + j, jcq + j + 1, cal(i, j)), addedge(jcq + j + 1, jcq + j, 0);
}
for (R int i = 1; i <= num; ++i)
{
in(a), in(b), in(c);
jcq = a * 605;
ncq = b * 605;
int sta = std::max(lef[a], lef[b] + c);
int endd = std::min(rig[b] + c, rig[a]) + 1;//一定注意要加1, 因为两个端点也要算在里面
for (R int j = sta; j <= endd; ++j)
addedge(jcq + j, ncq + j - c, inf), addedge(ncq + j - c, jcq + j, 0);
addedge(jcq + rig[a] + 1, ncq + rig[a] + 1 - c, inf);
addedge(ncq + rig[a] + 1 - c, jcq + rig[a] + 1, 0);
}
printf("%lld", Dinic_init());
}