题目链接:https://vjudge.net/problem/Gym-101190D
解题思路:
假设我们默认每个小时都是在吃,那么初始ans = ∑e[i],然后我将si变为si - ei,表示在i时刻选择睡觉时会获得si的收益。但是在k个连续的段中选择si的次数ms <= times <= k-me。
当ms == 0:
将问题转化为覆盖问题,那么每个点最多只能被覆盖k-me次,如果在i点选择了睡觉,那么就会将[i,i+k-1]的点都覆盖。这个问题跟我之前做的一题一模一样:点击这里
当ms>=0:
源点S = 0,汇点T = n + 1
对于i = 1,2,3,4...k-1,建立(i,i+1)的边,流量为+∞,花费为0的边。①
对于i = k,k+1,k+2...n,建立(i,i+1)的边,流量为k-me-ms,花费为0的边。②
对于i = 1,2,3,4...n,建立(i,min(i+k,T))的边,流量为1,花费为si的边。③
建立(S,1)流量为k-me,花费为0的边。④
明显在前两步建边中流过这些边的流量也都是无效流,也就是没有意义。没有意义的边的流量最大是k-me-ms,所以有效流肯定最少是k-me - (k-me-ms) = ms。这也就保证了流量上下界。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mx = 5e3 + 10;
const int mod = 998244353;
int n,K,ms,me,tot;
int s[mx],c[mx],head[mx];
int pre[mx];
bool vis[mx];
struct node{
int v,f,c;
int nxt;
}e[mx];
ll dis[mx];
void add(int u,int v,int f,int c){
e[tot] = {v,f,c,head[u]};
head[u] = tot++;
e[tot] = {u,0,-c,head[v]};
head[v] = tot++;
}
bool spfa(int S,int T)
{
for(int i=0;i<=T;i++){
dis[i] = -1e16;
pre[i] = -1;
}
queue <int> q;
q.push(S);
dis[S] = 0;
while(!q.empty()){
int now = q.front();
q.pop();
vis[now] = 0;
for(int i=head[now];~i;i=e[i].nxt)
{
int v = e[i].v;
if(e[i].f&&dis[v]<dis[now]+e[i].c){
dis[v] = dis[now] + e[i].c;
pre[v] = i;
if(!vis[v]){
vis[v] = 1;
q.push(v);
}
}
}
}
return dis[T] != -1e16;
}
ll maxflow(int S,int T){
ll ans = 0;
while(spfa(S,T)){
int mins = inf;
for(int i=pre[T];~i;i=pre[e[i^1].v]) mins = min(mins,e[i].f);
for(int i=pre[T];~i;i=pre[e[i^1].v])
{
e[i].f -= mins;
e[i^1].f += mins;
}
ans += dis[T];
}
return ans;
}
int main(){
freopen("delight.in","r",stdin);
freopen("delight.out","w",stdout);
scanf("%d%d%d%d",&n,&K,&ms,&me);
ll ans = 0;
memset(head,-1,sizeof(head));
int R = K - me;
for(int i=1;i<=n;i++) scanf("%d",s+i);
for(int i=1;i<=n;i++) scanf("%d",c+i),ans += c[i];
int S = 0,T = n + 1;
for(int i=1;i<=n;i++){
if(i+K>n) add(i,T,1,s[i]-c[i]);
else add(i,i+K,1,s[i]-c[i]);
}
for(int i=1;i<=n;i++){
if(i<K) add(i,i+1,inf,0);
else add(i,i+1,R-ms,0);
}
add(S,1,R,0);
printf("%lld\n",ans+maxflow(S,T));
for(int i=0;i<2*n;i+=2){
if(e[i].f) putchar('E');
else putchar('S');
}
puts("");
return 0;
}