bzoj 4842 [Neerc2016]Delight for a Cat 最小费用最大流,线性规划
题意:有n个小时,对于第i个小时,睡觉的愉悦值为si,打隔膜的愉悦值为ei,同时对于任意一段连续的k小时,必须至少有t1时间在睡觉,t2时间在打隔膜。如果要获得的愉悦值尽
量大,求最大的愉悦值和睡觉还是打隔膜的方案。(输出两行,第一行为最大愉悦值,第二行n个字符第i个字符为S则表示第i个小时在睡觉,为E则表示第i个小时在打隔膜)
我现在还没学线性规划的一系列东西(真丢人),写一下直观上的理解,学完线性规划和差分建图再回来写题解。
直观理解
首先当睡觉或者打隔膜任意一个活动满足其时间条件时,另一个也一定满足时间条件。
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条打隔膜边。
现在符合题意了
然后跑费用流。emm算是需要记忆的经典模型(其实只是我自己写不出来)?
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 #define LL long long 9 const int maxn=11000; 10 const int minf=1000000; 11 int n,k,t1,t2; 12 int SS,S,T; 13 LL a[maxn]={},b[maxn]={}; 14 struct nod{ 15 int x,y,v,next,rev;LL co; 16 }e[maxn*10]; 17 int head[maxn]={},tot=0; 18 LL dis[maxn]={}; int fa[maxn]={};bool vis[maxn]={}; 19 void init(int x,int y,int v,LL co){ 20 e[++tot].x=x;e[tot].y=y;e[tot].v=v;e[tot].co=co; 21 e[tot].next=head[x];head[x]=tot;e[tot].rev=tot+1; 22 23 e[++tot].x=y;e[tot].y=x;e[tot].v=0;e[tot].co=-co; 24 e[tot].next=head[y];head[y]=tot;e[tot].rev=tot-1; 25 } 26 queue<int>q; 27 bool SPFA(){ 28 memset(vis,0,sizeof(vis)); 29 memset(fa,0,sizeof(fa)); 30 memset(dis,31,sizeof(dis)); 31 //cout<<dis[1]<<endl; 32 q.push(S);vis[S]=1;dis[S]=0; 33 while(!q.empty()){ 34 int x=q.front();q.pop();vis[x]=0; 35 for(int i=head[x];i;i=e[i].next){ 36 if(e[i].v){ 37 if(dis[e[i].y]>dis[x]+e[i].co){ 38 dis[e[i].y]=dis[x]+e[i].co; 39 fa[e[i].y]=i; 40 if(!vis[e[i].y]){ 41 vis[e[i].y]=1; 42 q.push(e[i].y); 43 } 44 } 45 } 46 } 47 } 48 return fa[T]; 49 } 50 LL fyl(){ 51 int val=minf;LL ans=0; 52 for(int i=fa[T];i;i=fa[e[i].x])val=min(val,e[i].v); 53 for(int i=fa[T];i;i=fa[e[i].x]){ 54 ans+=e[i].co;e[i].v-=val;e[e[i].rev].v+=val; 55 } 56 return ans; 57 } 58 int main(){ 59 scanf("%d%d%d%d",&n,&k,&t1,&t2); 60 SS=n+1;S=SS+1;T=S+1; 61 for(int i=1;i<=n;i++)scanf("%lld",&a[i]); 62 for(int i=1;i<=n;i++)scanf("%lld",&b[i]); 63 for(int i=1;i<=n;i++)init(i,i+k>n?T:i+k,1,a[i]-b[i]); 64 for(int i=1;i<=n;i++)init(i,i+1>n?T:i+1,k-t1-t2,0); 65 for(int i=1;i<=k;i++)init(SS,i,minf,0); 66 init(S,SS,k-t1,0); 67 LL ans=0; 68 for(int i=1;i<=n;i++)ans+=a[i]; 69 while(SPFA())ans-=fyl(); 70 printf("%lld\n",ans); 71 for(int i=1;i<2*n;i+=2){ 72 if(!e[i].v)printf("E"); 73 else printf("S"); 74 }printf("\n"); 75 return 0; 76 }