【2017山东day7】养猫

【2017山东day7】养猫

Description

  你养了一只猫,为了让它快乐地成长,你需要合理地安排它每天的作息时间。假设一天分为$ n \(个时刻,猫在每个时刻要么是吃东西,要么是睡觉。在第\) i $个时刻,假如猫是去吃东西,那么它能获得愉悦值 \(ei\),假如是去睡觉,那么能获得的愉悦值为 \(si\)
  猫要成长,不仅仅需要快乐,还需要健康的作息。经过研究,对于每一个连续的长度为 k 的作息区间,即所有的时刻区间$ [i,i+k−1],1≤i≤n−k+1$,猫都要至少有 \(ms\)的时刻用来睡觉,$me $的时刻用来吃东西,这样猫才能健康成长。
  现在你想合理地安排一天中的这 n个时刻,使得猫在能健康成长的前提下,获得尽量多的愉悦值。

Input

  第一行四个整数 \(n,k,ms,me\)
  第二行包含\(n\)个整数,代表\(si\)
  第三行包含\(n\)个整数,代表\(ei\)

Output

  第一行一个整数,代表猫能获得的愉悦值。
  第二行 n 个字符,可以为 S 或 E,代表猫在某个时刻是在睡觉(S)还是在吃东西(E)。

Sample Input

5 4 2 2
4 8 6 2 2
4 6 9 6 0

Sample Output

29
SSEES

参考博客https://www.cnblogs.com/CQzhangyu/p/7894559.html

我们先全部吃。

\(y_i\)\(z_i\)是我们设出来的辅助变量,使得\(\leq ,\ge\)变成了\(=\)
\[ \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\\ ...\\ x_{n-k+1}+x_{n-k+2}+...+x_n=t_1+y_{n-k+1}\\ x_{n-k+1}+x_{n-k+2}+...+x_n=k-t_2-z_{n-k+1} \end{cases} \]
我们保留第\(1\)个和最后一个方程,其他的方程与前一个做差分,得到:
\[ \begin{cases} x_1+x_2+...+x_k=t_1+y_1\\ k-t_2=x_{n-k+1}+x_{n-k+2}+...+x_n+z_{n-k+1}\\ y_i+z_i=k-t_1-t_2(1\leq i\leq n-k+1)\\ x_{i+k}+k-t_1-t_2=x_i+z_i+y_{i+1}(1\leq i\leq n-k)\\ \end{cases} \]
我们整理一下,使得每个未知量恰好在左边出现一次,恰好在右边出现一次。

我们拿方程作为节点,假设方程左边的常数为\(LC\),右边的常数为\(RC\),我们连\((S,i,LC,0),(i,T,RC,0)\)。(最后一维表示费用)。

然后对于未知量\(x_i\),假设它出现在\(a\)的左边,\(b\)的右边,我们连\((b,a,1,S_i-E_i)\)

跑最大费用最大流。

我开始时犯了常识错误,即使最长路为负也要加上贡献,因为我们要先保证最大流。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 4005

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

int n,k,t1,t2;
ll S[N],E[N],w[N];
int SS,TT;
struct road {
    int to,next;
    ll f,c;
}s[N<<3];

int h[N],cnt=1;
void add(int i,int j,int f,int c) {
    s[++cnt]=(road) {j,h[i],f,c};h[i]=cnt;
    s[++cnt]=(road) {i,h[j],0,-c};h[j]=cnt;
}

ll ans;
queue<int>q;
bool in[N];
ll dis[N];
int fr[N],e[N];

bool spfa(int S,int T) {
    memset(dis,-0x3f,sizeof(dis));
    dis[S]=0;
    q.push(S);
    while(!q.empty()) {
        int v=q.front();q.pop();
        in[v]=0;
        for(int i=h[v];i;i=s[i].next) {
            int to=s[i].to;
            if(s[i].f&&dis[to]<dis[v]+s[i].c) {
                dis[to]=dis[v]+s[i].c;
                fr[to]=v;
                e[to]=i;
                if(!in[to]) {
                    in[to]=1;
                    q.push(to);
                }
            }
        }
    }
    if(dis[T]<-1e9) return 0;
    ll maxflow=1e9;
    for(int i=T;i;i=fr[i]) {
        maxflow=min(maxflow,s[e[i]].f);
    }
    ans+=maxflow*dis[T];
    for(int i=T;i;i=fr[i]) {
        s[e[i]].f-=maxflow;
        s[e[i]^1].f+=maxflow;
    }
    return 1;
}

int edge_id[N];
int main() {
    n=Get(),k=Get(),t1=Get(),t2=Get();
    for(int i=1;i<=n;i++) S[i]=Get();
    for(int i=1;i<=n;i++) E[i]=Get();
    for(int i=1;i<=n;i++) ans+=E[i];
    for(int i=1;i<=n;i++) w[i]=S[i]-E[i];
    TT=2*n+2;
    
    add(1,TT,t1,0);
    add(SS,2,k-t2,0);
    for(int i=1;i<=n-k+1;i++) add(i+2,TT,k-t1-t2,0);
    for(int i=1;i<=n-k;i++) {
        add(SS,i+n-k+3,k-t1-t2,0);
    }
    
    for(int i=1;i<=k;i++) {
        edge_id[i]=cnt+1;
        if(i>=n-k+1) add(2,1,1,w[i]);
        else add(n-k+3+i,1,1,w[i]);
    }
    
    for(int i=1;i<=n-k;i++) {
        edge_id[i+k]=cnt+1;
        if(i+k>=n-k+1) add(2,i+n-k+3,1,w[i+k]);
        else add(i+n+3,i+n-k+3,1,w[i+k]);
    }
    add(1,3,1e9,0);
    for(int i=1;i<=n-k;i++) add(i+n-k+3,i+3,1e9,0);
    for(int i=1;i<=n-k;i++) add(i+n-k+3,i+2,1e9,0);
    add(2,n-k+3,1e9,0);
    while(spfa(SS,TT));
    cout<<ans<<"\n";
    for(int i=1;i<=n;i++) {
        if(s[edge_id[i]].f) cout<<"E";
        else cout<<"S";
    }
    return 0;
}

转载于:https://www.cnblogs.com/hchhch233/p/10555789.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值