王子 [费用流]
题意
给定$n,k,p,q$,现在要给一段长度为n的格子染黑白,第$i$个格子染成黑色得到$a_i$分,白色$b_i$分
要求连续的$k$个格子中要有至少$p$个黑的,$q$和白的
求最大得分
思路
一眼是没想法的......瞄了一眼题解看到“网络流”三个大字,就会了
还是要多想一些方法,多试试,因为这种题看着不是dp就是什么鬼畜的转化,那转化模型肯定先看是不是网络流
考虑序列模型的经典网络流转化方法
本题中的核心限制是对于每一段$k$区间的颜色数限制
可以看到实际上这个$p,q$就是限制黑色格子的数量是$[p,k-q]$
同时这个限制对于每一个格子而言,这个格子参与$k$个区间的限制
我们考虑这样一个方法:
首先把所有的都涂成白色,然后用跨越一个$k$区间的一点流量来代表变成一个黑格子带来的影响,其他的从$i$到$i+1$的代表一个白格子
那么这样我们把白格子边设成流量上限为$k-q-p$上限,费用为0,代表额外的白变黑的数量上限
黑格子边显然容量为1,费用为对应的格子的$b_i-a_i$
一些细节注意:
首先这个跨越的黑格子边,从$i$出发,终点在$k+i$不是在$k+i-1$
然后注意最开始的$k$个点,没有前驱去到达它们,那么建立一个辅助节点$aux$,从$s->aux$连一条容量为$k-q$的(限制一下),再从$aux$连向$1$到$k$号点
实现上可以把费用流的$ans$初值设为所有白格子分数的和,然后用上面定义的费用直接算就可以了
费用流推荐使用spfa魔改版zkw多路增广,不过本题中单路多路其实差距不大,$EK$还可能更快(因为图的形态问题)
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<queue>
#define ll long long
using namespace std;
inline ll read(){
ll re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
ll n,m,l,r,cnte=1,first[1010],dis[1010],vis[1010],ans=0,maxf=0;
struct edge{
ll to,next,w,cap;
}a[20010];
inline void add(ll u,ll v,ll w,ll cap){
a[++cnte]=(edge){v,first[u],w,cap};first[u]=cnte;
a[++cnte]=(edge){u,first[v],-w,0,};first[v]=cnte;
}
queue<ll>q;
bool spfa(ll s,ll t){
ll i,u,v;
for(i=s;i<=t+1;i++) dis[i]=-111111111111111ll,vis[i]=0;
vis[t]=1;dis[t]=0;q.push(t);
while(!q.empty()){
u=q.front();q.pop();vis[u]=0;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;
if(!a[i^1].cap) continue;
if(dis[v]!=-111111111111111ll&&(dis[v]>=dis[u]+a[i^1].w)) continue;
dis[v]=dis[u]+a[i^1].w;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
return dis[s]!=-111111111111111ll;
}
ll dfs(ll u,ll t,ll lim){
if(u==t||!lim) return lim;
ll i,v,f,flow=0;vis[u]=1;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;if(vis[v]) continue;
if(dis[v]==dis[u]-a[i].w&&(f=dfs(v,t,min(lim,a[i].cap)))){
a[i].cap-=f;
a[i^1].cap+=f;
flow+=f;
lim-=f;
ans+=f*a[i].w;
if(!lim){vis[u]=0;return flow;}
}
}
dis[u]=-111111111111111ll;
return flow;
}
void mcmf(ll s,ll t){
while(spfa(s,t)){
memset(vis,0,sizeof(vis));
vis[t]=1;
while(vis[t]){
memset(vis,0,sizeof(vis));
maxf+=dfs(s,t,1e9);
}
}
}
ll x[1010],y[1010];
int main(){
memset(first,-1,sizeof(first));
n=read();m=read();l=read();r=m-read();ll i;
for(i=1;i<=n;i++) x[i]=read(),y[i]=read(),ans+=y[i];
add(0,n+2,0,r);
for(i=1;i<=m;i++) add(n+2,i,0,1);
for(i=1;i<=n;i++){
add(i,i+1,0,r-l);
add(i,((i<=n-m)?i+m:n+1),x[i]-y[i],1);
}
mcmf(0,n+1);
cout<<ans<<'\n';
}