[Neerc2016]Delight for a Cat

Delight for a Cat

题解

网络流板子题。

通常的网络流是不会出现这种一个点有两个方向可以走的,而且这样也不大好处理。

于是,我们考虑差分建图。

先假设它选的全部都是睡觉,求出\sum_{i=1}^{n}s_{i}的值,再减去打隔膜的时间差。这样就成了一个常规的最小费用最大流。

因为连续k段中一定有t_{1}个时间在睡觉,于是总流量为k- t_{1}。于是限制源点流量为k- t_{1}

然后就是连续k段只有一定个被选的常规操作,从ii+k连一条流量为1,边权为s_{i}-e_{i}的边,也就是这一天改选打隔膜的时间差。若连出去了就连向汇点。从源点向1-k的点各连容量为1的边,保证区间大小,反正总流量不会超过k-t_{1}

为了限制下界为t_{2},我们还需在ii+ 1间连一条容量为k-t_{1}-t_{2}的边。因为到汇点的流一定是最大的,所以流肯定会在前面跑满甚至跑过它的下界t_{2},再在这里跑这条边。这样才能保证总流量是最大的,及源点的流一定是满的,再来满足总费用最小。这样就巧妙的实现了下界为t_{2},上界为k-t_{1}。还需在第n个点向汇点连边,让还未跑的流流入汇点。

图就这样建好了,最后跑一遍网络流即可。

源码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL; 
#define int LL
const int INF=0x7f7f7f7f7f7f;
#define MAXN 5005
#define gc() getchar()
template<typename _T>
inline void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}
int dis[MAXN],vis[MAXN],pre[MAXN];
int head[MAXN],tot,s1,t1;
int from[MAXN<<1],to[MAXN<<1];
int nxt[MAXN<<1],paid[MAXN<<1],cap[MAXN<<1];
void addEdge(int u,int v,int flow,int cost){
	//printf("%d %d %d %d\n",u,v,flow,cost);
	from[++tot]=u;to[tot]=v;paid[tot]=cost;
	cap[tot]=flow;nxt[tot]=head[u];head[u]=tot;
}
void addedge(int u,int v,int flow,int cost){
	//printf("%d %d %d %d\n",u,v,flow,cost);
	addEdge(u,v,flow,cost);addEdge(v,u,0,-cost);
}
int EK(){
	int res=0,sum=0;
	while(1){
		for(int i=0;i<=t1;i++) dis[i]=INF,vis[i]=0,pre[i]=-1; 
		queue<int> q;while(!q.empty()) q.pop();
		dis[s1]=0;vis[s1]=1;q.push(s1);
		while(!q.empty()){
			int now=q.front();q.pop();vis[now]=0;
			//printf("%d\n",now);
			for(int i=head[now];~i;i=nxt[i]){
				int v=to[i];//printf("%d-->%d %d %d %d\n",now,v,dis[now],cap[i],dis[v]);
				if(cap[i]>0&&dis[v]>dis[now]+paid[i]){
					//printf("%d-->%d\n",now,v);
					dis[v]=dis[now]+paid[i];pre[v]=i;
					if(!vis[v]) q.push(v),vis[v]=1;
				}
			}
		}
		//printf("dis%d %d\n",res,dis[t1]);
		if(dis[t1]>INF-1) return res;int minn=INF;
		for(int i=pre[t1];~i;i=pre[from[i]])minn=min(minn,cap[i]);
		for(int i=pre[t1];~i;i=pre[from[i]])cap[i]-=minn,cap[i^1]+=minn;
		res+=dis[t1]*minn;sum+=minn;
		//printf("%d %d %d\n",res,minn,dis[t]);
	}
}
int n,k,T1,T2,sums;
int s[MAXN],e[MAXN];
signed main(){
	memset(head,-1,sizeof(head));
	read(n);read(k);read(T1);read(T2);s1=n+1;t1=n+3;tot=-1;
	for(int i=1;i<=n;i++)read(s[i]),sums+=s[i];
	for(int i=1;i<=n;i++)read(e[i]);
	for(int i=1;i<=n;i++)addedge(i,i+k<=n?i+k:t1,1,s[i]-e[i]);
	for(int i=1;i<=k;i++)addedge(n+2,i,INF,0);addedge(s1,n+2,k-T1,0);
	for(int i=1;i<n;i++)addedge(i,i+1,k-T1-T2,0);addedge(n,t1,k-T1-T2,0);
	printf("%lld\n",sums-EK());
	for(int i=0;i<2*n;i+=2)
		if(!cap[i])printf("E");
		else printf("S");
    return 0;
}

谢谢!!!

发布了117 篇原创文章 · 获赞 154 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Tan_tan_tann/article/details/104066528
cat