【BZOJ4842】[Neerc2016]Delight for a Cat 線性規划+費用流


【BZOJ4842】[Neerc2016]Delight for a Cat

Description

ls是一個特別墮落的小朋友,對於n個連續的小時,他將要么睡覺要么打隔膜,一個小時內他不能既睡覺也打隔膜,因此一個小時內他只能選擇睡覺或者打隔膜,當然他也必須選擇睡覺或打隔膜,對於每一個小時,他選擇睡覺或打隔膜的愉悅值是不同的,對於第i個小時,睡覺的愉悅值為si,打隔膜的愉悅值為ei,同時又有一個奧妙重重的規定:對於任意一段連續的k小時,ls必須至少有t1時間在睡覺,t2時間在打隔膜。那么ls想讓他獲得的愉悅值盡量大,他該如何選擇呢?

Input

第一行四個整數,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)表示打隔膜的愉悅值。

Output

第一行輸出最大的愉悅值。
接下來一行輸出一個長度為n的字符串
第i個字符為E則代表第i小時在打隔膜,第i個字符為S則代表第i個小時在睡覺。

Sample Input

10 4 1 2
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1

Sample Output

69
EEESESEESS

題解:我們先令所有時間都打隔膜,於是在i時刻睡覺的收益就變成了si-ei。我們令第i時刻是否睡覺的狀態為xi(xi=0或1),那么限制條件就變成了如下不等式:$t_1 \le x_i+x_{i+1}+...+x_{i+k-1} \le k-t_2$。我們想要最大化$\sum x_i*(s_i-e_i)$,這顯然就變成了一個線性規划問題。如何處理線性規划問題?列單純形表

然而今天還是去學了用費用流解線性規划的方法。我們先將不等式轉化成標准型,即加入新變量y,z($y,z \in [0,+ \infty ]$)使不等式變成等式:$t_1+y_i=x_i+x_{i+1}+...+x_{i+k-1}=k-t_2-z_i$,接着列出方程組:

$\begin{cases}x_1+x_2+...+x_k=t_1+y_1\\ x_1+x_2+...+x_k=k-t_2-z_1\\ x_2+x_3+...+x_{k+1}=t_1+y_2\\ x_2+x_3+...+x_{k+1}=k-t_2-z_2\\ ...\end{cases}$

根據一個慣用的套路,我們在最下面加入不等式0=0,然后差分,並整理一下:

$\begin{cases}x_1+x_2+...+x_k=t_1+y_1\\ y_1+z_1=(k-t_1-t_2)\\ x_{k+1}+(k-t_1-t_2)=x_2+z_1+y_2\\ y_2+z_2=(k-t_1-t_2)\\ ...\\k-t_2=x_{n-k+1}+x_{n-k+2}+...+x_k+z_{n-k+1}\end{cases}$

我們發現每個變量在等式的左側和右側都各出現一次,我們將等式看成點,等式左邊看成流出,等式右面看成流入。對於變量x,我們從它流出的點向流入的點連一條邊,容量為1費用為si-ei;對於變量y,z,它的容量為$\infty$,費用為0;對於常數項,如果是流出則從該點連向T,流入則從S連向該點,容量為常數項的大小。接着跑最大費用最大流,輸出方案時看一下對應的邊的容量即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
ll ans,tot;
int n,k,t1,t2,cnt,S,T;
int inq[2010],to[100010],next[100010],flow[100010],pe[2010],pv[2010],head[2010],pos[2010],A[2010],B[2010];
ll cost[100010],dis[2010];
queue<int> q;
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
inline void add(int a,int b,int c,int d)
{
	if(!d)	return ;
	to[cnt]=b,cost[cnt]=c,flow[cnt]=d,next[cnt]=head[a],head[a]=cnt++;
	to[cnt]=a,cost[cnt]=-c,flow[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
}
inline int bfs()
{
	memset(dis,0x80,sizeof(dis));
	q.push(S),dis[S]=0;
	int u,i;
	while(!q.empty())
	{
		u=q.front(),q.pop(),inq[u]=0;
		for(i=head[u];i!=-1;i=next[i])
		{
			if(dis[to[i]]<dis[u]+cost[i]&&flow[i])
			{
				dis[to[i]]=dis[u]+cost[i],pv[to[i]]=u,pe[to[i]]=i;
				if(!inq[to[i]])	inq[to[i]]=1,q.push(to[i]);
			}
		}
	}
	return dis[T]>ll(0x8080808080808080ll);
}
int main()
{
	n=rd(),k=rd(),t1=rd(),t2=rd();
	S=0,T=((n-k+1)<<1)+2;
	memset(head,-1,sizeof(head));
	int i;
	for(i=1;i<=n;i++)	A[i]=rd();
	for(i=1;i<=n;i++)	B[i]=rd(),tot+=B[i];
	for(i=1;i<=n;i++)	pos[i]=cnt+1,add(max(1,((i-k)<<1)+1),min((i<<1)+1,((n-k+1)<<1)+1),A[i]-B[i],1);
	add(S,1,0,t1);
	for(i=1;i<=n-k+1;i++)
	{
		add(i<<1,(i<<1)-1,0,1<<30),add(i<<1,(i<<1)+1,0,1<<30);
		add(S,i<<1,0,k-t1-t2);
		if(i!=n-k+1)	add((i<<1)+1,T,0,k-t1-t2);
	}
	add(((n-k+1)<<1)+1,T,0,k-t2);
	while(bfs())
	{
		int mf=1<<30;
		for(i=T;i!=S;i=pv[i])	mf=min(mf,flow[pe[i]]);
		ans+=dis[T]*mf;
		for(i=T;i!=S;i=pv[i])	flow[pe[i]]-=mf,flow[pe[i]^1]+=mf;
	}
	printf("%lld\n",tot+ans);
	for(i=1;i<=n;i++)
	{
		if(flow[pos[i]])	printf("S");
		else	printf("E");
	}
	return 0;
}
//2 2 0 0 1 2 2 1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM