Codeforces Gym 101190 NEERC 16 .D Delight for a Cat (上下界的费用流)
ls是一个特别堕落的小朋友,对于n个连续的小时,他将要么睡觉要么打隔膜,一个小时内他不能既睡觉也打隔膜
,因此一个小时内他只能选择睡觉或者打隔膜,当然他也必须选择睡觉或打隔膜,对于每一个小时,他选择睡觉或
打隔膜的愉悦值是不同的,对于第i个小时,睡觉的愉悦值为si,打隔膜的愉悦值为ei,同时又有一个奥妙重重的
规定:对于任意一段连续的k小时,ls必须至少有t1时间在睡觉,t2时间在打隔膜。那么ls想让他获得的愉悦值尽
量大,他该如何选择呢?
题意:就是N天,每天可以选择S或者E,每一天S或者E有自己的收益,求最大收益,且满足每个连续K天,只是有Ms天选择了S,Me天选择了E。
输出最大收益,以及对应的方案。
思路:和上一题有点像,不过加了下界,问题不大,直接去看题解就好了。
只需要把相邻的边容量改为最大-最小即可,费用为,表示最多流出去mx-mn这么多,留在这里的流量保证了下界。 对于输出方案,只需要看对应的流是否饱和即可。
#include<bits/stdc++.h> #define ll long long #define maxn 1010 using namespace std; int To[maxn*6],Laxt[maxn],Next[maxn*6],cap[maxn*6],cost[maxn*6],tag[maxn]; int S,T,cnt=1; ll dis[maxn],ans;//建边的时候注意开对应大小的空间 bool inq[maxn],vis[maxn]; deque<int>q; void add(int u,int v,int c,int cc) { Next[++cnt]=Laxt[u];Laxt[u]=cnt;To[cnt]=v;cap[cnt]=c;cost[cnt]=cc; } bool spfa() { for(int i=0;i<=T;i++) inq[i]=0; for(int i=0;i<=T;i++) dis[i]=1LL<<60; //这样更新,必须保证T的编号最大 inq[T]=1; dis[T]=0; q.push_back(T); while(!q.empty()) { int u=q.front(); q.pop_front(); inq[u]=0; for(int i=Laxt[u];i;i=Next[i]) { int v=To[i]; if(cap[i^1]&&dis[v]>dis[u]-cost[i]) { dis[v]=dis[u]-cost[i]; if(!inq[u]){ inq[v]=1; if(q.empty()||dis[v]>dis[q.front()]) q.push_back(v); else q.push_front(v); } } } } return dis[S]<(1LL<<60); } int dfs(int u,int flow) { vis[u]=1; if(u==T||flow==0) return flow; int tmp,delta=0; for(int i=Laxt[u];i;i=Next[i]) { int v=To[i]; if((!vis[v])&&cap[i]&&dis[v]==dis[u]-cost[i]) { tmp=dfs(v,min(cap[i],flow-delta)); delta+=tmp; cap[i]-=tmp; cap[i^1]+=tmp; } } return delta; } int s[maxn],e[maxn]; int main() { int N,K,mn,mx,i; scanf("%d%d%d%d",&N,&K,&mx,&mn); for(i=1;i<=N;i++) scanf("%d",&s[i]),ans+=s[i]; for(i=1;i<=N;i++) scanf("%d",&e[i]),e[i]-=s[i]; mx=K-mx; S=0; T=N+2; int SS=N+1; add(S,SS,mx,0); add(SS,S,0,0); for(i=1;i<=K;i++){ //先约定前面K个数,先选。 add(SS,i,mx,0); add(i,SS,0,0); } for(i=1;i<=N;i++) add(i,i+1>N?T:i+1,mx-mn,0),add(i+1>N?T:i+1,i,0,0); for(i=1;i<=N;i++) add(i,i+K>N?T:i+K,1,-e[i]),tag[i]=cnt,add(i+K>N?T:i+K,i,0,e[i]); while(spfa()){ vis[T]=1; while(vis[T]){ for(i=0;i<=T;i++) vis[i]=0; int tmp=dfs(S,mx); ans-=(ll)tmp*dis[S]; } } printf("%I64d\n",ans); for(i=1;i<=N;i++) if(cap[tag[i]]) putchar('S'); else putchar('E'); return 0; }
It is your time to fight!