网络流的好题目
三次函数的形式将我迷惑了,以为是一道数学题
其实这道题的突破口是它奇怪的限制
应该自然联想到网络流!
这里是最小割
不考虑限制,就是对于每个函数每个可能的取值
x
(
l
≤
x
≤
r
)
x(l\leq x\leq r)
x(l≤x≤r),从
S
S
S到
T
T
T连一条链,断掉一条边代表你选了
f
(
x
)
f(x)
f(x)作为这个函数的值,容量为
f
(
x
)
f(x)
f(x)
那这样岂不是变成了“最大割”问题?
容量取个相反数不就是最小割?
当然,你会连
r
−
l
+
2
r-l+2
r−l+2条边,值却只有
r
−
l
+
1
r-l+1
r−l+1个,所以
S
S
S的出边或
T
T
T的入边有一条边容量是
i
n
f
inf
inf,我将
S
S
S的出边容量定为
i
n
f
inf
inf,那么每个点的出边被断代表选这个点
考虑如何加上限制,其实有个最小割这个思路,限制也不难想。对于一组
(
u
,
v
,
d
)
(u,v,d)
(u,v,d),
u
x
向
v
x
−
d
u_x向v_{x-d}
ux向vx−d连一条容量为
i
n
f
inf
inf的边,
i
n
f
inf
inf不可能被割掉,所以选择了
u
x
u_x
ux就必须选择
v
x
−
d
v_{x-d}
vx−d或以后的边割(选
v
x
−
d
v_{x-d}
vx−d前的边无法改变连通性)
如果
v
x
−
d
v_{x-d}
vx−d没值了怎么办?
这就代表
u
x
u_x
ux根本不能选,因为没有对应的
v
x
−
d
v_{x-d}
vx−d满足限制
向
T
T
T连一条
i
n
f
inf
inf边即可
然后跑个最小割就能过
实现细节粗节 :
你会发现,我们的容量有可能是负数!
加上一个大值
C
C
C使之变成正整数。
答案即为最小割
−
n
∗
C
-n*C
−n∗C(我们知道
1
1
1个函数
1
1
1个取值,也就是一共只会被割
n
n
n条边)
怎么判无解?
当最小割
≥
i
n
f
\geq inf
≥inf时,说明你割掉了一条
i
n
f
inf
inf边,这是无解的情况
当然
i
n
f
inf
inf值要设的足够大
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 700005
#define ll long long
#define C 200000000
#define D 205
#define mem(a) memset(a,0,sizeof(a))
#define S 400001
#define T 400002
#define inf 100000000000
using namespace std;
ll cur[N],gap[N],dis[N],f[N<<1][4],q[N];
ll i,j,k,m,n,o,p,l,s,t,times,k1,k2,k3,k4,last,x,y,d,ans,r;
ll a[105][205],tot;
struct node{
ll l,r;
}b[10005];
void insert(ll x,ll y,ll z)
{
if (z!=inf) z=-z+C;
f[++t][1]=y,f[t][2]=q[x],f[t][3]=z,q[x]=t;
f[++t][1]=x,f[t][2]=q[y],f[t][3]=0,q[y]=t;
}
ll dfs(ll t,ll flow)
{
if (t==T) return flow;
ll have=0;
for (ll k=cur[t];k;k=f[k][2])
{
if (dis[f[k][1]]+1==dis[t]&&f[k][3])
{
cur[t]=k;
ll now=dfs(f[k][1],min(flow-have,f[k][3]));
f[k][3]-=now,f[k^1][3]+=now,have+=now;
if (flow==have) return flow;
}
}
cur[t]=q[t];
if (!(--gap[dis[t]])) dis[S]=T;
++gap[++dis[t]];
return have;
}
ll cal(ll x) {return k1*x*x*x+k2*x*x+k3*x+k4;}
int main()
{
freopen("sleep.in","r",stdin);
freopen("sleep.out","w",stdout);
scanf("%lld",×);
while (times--)
{
mem(cur),mem(gap),mem(dis),mem(f),mem(q),t=tot=1;
scanf("%lld%lld",&n,&m);
for (i=1;i<=n;i++)
{
scanf("%lld%lld%lld%lld%lld%lld",&k1,&k2,&k3,&k4,&l,&r);
insert(S,++tot,inf);a[i][l+D]=last=tot;
for (j=l+1,k=2;j<=r;j++,k++)
{
insert(last,++tot,cal(j-1));
a[i][j+D]=last=tot;
}
insert(tot,T,cal(r));
b[i]=(node){l,r};
}p=0;
for (i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&x,&y,&d);
o=1e9;
for (j=b[x].l;j<=b[x].r;j++)
{
if (j-d<=b[y].r)
{
o=1;
}
if (j-d>=b[y].l&&j-d<=b[y].r)
{
insert(a[x][j+D],a[y][j-d+D],inf);
}
if (j-d>=b[y].r+1) insert(a[x][j+D],T,inf);
}
if (o==1e9)
{
p=1;//break;
}
}
/* if (p)
{
puts("mei ji ge");
continue;
}*/
ans=0;
while (dis[S]<T)
ans+=dfs(S,inf);
if (ans>=inf)
{
puts("mei ji ge");
continue;
}
printf("%lld\n",n*C-ans);
}
return 0;
}