51nod2939 Delight for a Cat

该博客探讨了一个关于小朋友ls在连续小时内选择睡觉或打隔膜以获得最大愉悦值的问题。ls需要在每个连续的k小时内至少有t1时间睡觉和t2时间打隔膜。文章通过构建网络流模型求解最优策略,并提供了C++代码实现。
摘要由CSDN通过智能技术生成

2939 Delight for a Cat

ls是一个特别堕落的小朋友,对于n个连续的小时,他将要么睡觉要么打隔膜,一个小时内他不能既睡觉也打隔膜,因此一个小时内他只能选择睡觉或者打隔膜,当然他也必须选择睡觉或打隔膜,对于每一个小时,他选择睡觉或打隔膜的愉悦值是不同的,对于第i个小时,睡觉的愉悦值为si,打隔膜的愉悦值为ei,同时又有一个奥妙重重的规定:对于任意一段连续的k小时,ls必须至少有t1时间在睡觉,t2时间在打隔膜。那么ls想让他获得的愉悦值尽量大,他该如何选择呢?

输入

第一行四个整数,n,k(1<=k<=n<=1000),t1,t2(0<=t1,t2<=k;t1+t2<=k),含义如上所述。
接下来一行n个整数,第i个整数si(0<=si<=1e9)表示睡觉的愉悦值。
接下来一行n个整数,第i个整数ei(0<=ei<=1e9)表示打隔膜的愉悦值。

输出

第一行输出最大的愉悦值。
接下来一行输出一个长度为n的字符串
第i个字符为E则代表第i小时在打隔膜,第i个字符为S则代表第i个小时在睡觉。

数据范围

27% 2 <= n <= 90 2 <= k <= 15
40% 2 <= n <= 500 2 <= k <= 65
100% 2 <= n <= 1000 2 <= k <= 1000

输入样例

输入样例1:
10 4 1 2
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
输入样例2:
1 1 0 1
992949351
743176969
输入样例3:
2 2 1 0
738091870 236758424
921608564 874185073

输出样例

输出样例1:
69
EEESESEESS
输出样例2:
743176969
E
输出样例3:
1612276943
SE

解析:

首先当睡觉或者打隔膜任意一个活动满足其时间条件时,另一个也一定满足时间条件。

1.先考虑打隔膜的时间必须为t2时怎么解决。

设起初所有时间都在睡觉,那么我们需要这个睡觉的权值和-最小的sigma( si-ei )。

对每第i个点向第i+k个点引一条边,不存在则引向结尾的点,流量为1,消费为si-ei。(这条边表示第 i 小时选择了打隔膜)

虚点引到[ 1 , k ]点各一条边,流量无限,消费为0。 起始点引向虚点一条边,流量为t2。

这样建图保证了第i个点和第i+k个点一定一起取,从而保证了每个区间最后都一定有t2个时间在打隔膜(可以证明 : 必须有t2个时间打隔膜时,一定有i和i+k一起取)。

2.现在考虑可以随意使用的k-t1-t2个时间。

对第i个点向第i+1个点引一条边,流量为k-t1-t2,消费为0。此时起始点向虚点的边流量应变为k-t1。

显然有t2条路的选择和1中的没有什么分别。但i到i+1的路和起始点更多的流量给选择更多的打隔膜边留下了机会,我们还可以在每个k区间多选k-t1-t2条打隔膜边。

放代码:

#include<bits/stdc++.h>
#define maxn 1005
#define maxm 10005
#define LL long long
#define inf 0x3f3f3f3f
using namespace std;
int n,K,t1,t2;
LL s[maxn],e[maxn],cst[maxm],h[maxn],ans;
int S,T,buf[maxn],info[maxn],Prev[maxm],to[maxm],cap[maxm],vis[maxn],id[maxn],cnt_e=1;
void Node(int u,int v,int c,LL ct){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cap[cnt_e]=c,cst[cnt_e]=ct; }
void Line(int u,int v,int c,LL ct){
	Node(u,v,c,ct),Node(v,u,0,-ct);
}
bool SPFA(){
	static queue<int>q;
	static bool inq[maxn];
	memcpy(info,buf,sizeof info);
	memset(h,-0x3f,sizeof h);
	q.push(T),h[T]=0;
	for(int u;!q.empty();){
		u=q.front(),q.pop();
		for(int i=info[u],v;i;i=Prev[i]) if(cap[i^1] && h[v=to[i]] < h[u] + cst[i^1]){
			h[v] = h[u] + cst[i^1];
			if(!inq[v]) inq[v]=1,q.push(v);
		}
		inq[u]=0;
	}
	return h[S] > h[0];
}
int aug(int u,int mx){
	if(u == T) return ans+=mx*h[S],mx;
	int st = mx , inc;vis[u] = 1;
	for(int &i=info[u],v;i;i=Prev[i]) if(cap[i] && h[v=to[i]] + cst[i] == h[u] && !vis[v]){
		inc = aug(v,min(cap[i] , st));
		st -= inc , cap[i] -= inc , cap[i^1] += inc;
		if(!st) return vis[u] = 0,mx;
	}
	vis[u] = 0;
	return mx - st;
}
int main(){
	scanf("%d%d%d%d",&n,&K,&t1,&t2);
	for(int i=1;i<=n;i++) scanf("%lld",&s[i]),ans+=s[i];
	for(int i=1;i<=n;i++) scanf("%lld",&e[i]),Line(i,min(i+K,n+1),1,e[i]-s[i]),id[i]=cnt_e;
	for(int i=1;i<=n;i++) Line(i,i+1,K-t1-t2,0);
	Line(S=n+3,n+2,K-t1,0);T = n+1;
	for(int i=1;i<=K;i++) Line(n+2,i,inf,0);
	for(memcpy(buf,info,sizeof info);SPFA();) aug(S,inf);
	printf("%lld\n",ans);
	for(int i=1;i<=n;i++)	
		if(cap[id[i]]) putchar('E');
		else putchar('S');
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值