P6967 [NEERC2016]Delight for a Cat 题解

第一眼:这个是 dp ?

第二眼:神马 dp 神仙题啊,太弱了诶

第三眼:一发上网络流建模!

于是就有了这篇题解。

这里给出一个线性规划理解的最大流做法。

假设猫睡了 $n$ 天,则有收益 $\sum_{i=1}^n s_i$ ,然后所做的事情就是把某些天的睡觉改成吃饭。

设 $x_i\in\{0, 1\}$ 表示第 $i$ 天干的事情。 $x_i=0$ 表示睡觉, $x_i=1$ 表示吃饭。

依题意得

$\forall i\in[1,n-k+1],
me\leqslant\sum_{j=i}^{i+k-1}x_j\leqslant k-ms$

$\forall i\in[1,n]\cap\mathbb{Z},x_i\in\{0,1\}$

$\text{maximize}\{\sum_{i=1}^n (e_i-s_i)x_i\}$

再设变量 $y$ 和 $z$ 。得:

$x_1+x_2+...+x_k=me+y_1$

$x_1+x_2+...+x_k=k-ms-z_1$

$x_2+x_3+...+x_{k+1}=me+y_2$

$x_2+x_3+...+x_{k+1}+z_2=k-ms-z_2 $

$...$

$x_{n-k+1}+x_{n-k+2}+...+x_{n-1}+x_n=me+y_{n-k+1}$

$x_{n-k+1}+x_{n-k+2}+...+x_{n-1}+x_n=k-ms-z_{n-k+1}$

增加恒等式 $0=0$ ,并且设常数 $C=k-ms-me$ 。得:

$x_1+x_2+...+x_k=me+y_1 $

$y_1+z_1=C $

$x_{k+1}+C=x_1+y_2+z_1 $

$y_2+z_2=C $

$... $

$x_n+C=x_{n-k}+y_{n-k+1}+z_{n-k} $

$y_{n-k+1}+z_{n-k+1}=C$

$k-ms=x_{n-k+1}+x_{n-k+2}+...+x_n+z_{n-k+1} $

所有未知量和满足“流入=流出”,每一个式子也可以看作“流入=流出”,所以使用网络流算法。

为什么不用单纯型?因为不容易输出方案。~~其实是本人不会~~

因为有容量,还有费用 $e_i-s_i$ (仅限于表示 $x_i$ 的边),所以使用**最大费用最大流**来求解。

答案为 $\sum s_i + \text{MCMF}$ 。

如何判断方案?找出所有表示 $x_i$ 的边,满流就是吃饭,空流就是睡觉。

由于本人使用EK算法,所以是 $\Theta(nm^2)$ 。

# 代码时光到~

#include<cstdio>
#include<cstring>
#include<iostream>
#define int long long
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
int n,k,ms,me,_s[1010],_e[1010],sum;
bool vis[50010];int id[1010];
int front,rear,q[10000010];
int cnt=-1,head[50010],d[50010];
int s,t,p1[50010],p2[50010];
int pre[100010],ver[100010],cap[100010],cost[100010];
void adde(int u,int v,int f,int w){
    pre[++cnt]=head[u];ver[cnt]=v;cap[cnt]=f;cost[cnt]=w;head[u]=cnt;
    pre[++cnt]=head[v];ver[cnt]=u;cap[cnt]=0;cost[cnt]=-w;head[v]=cnt;
}
bool SPFA(int src,int &fs,int &cs){
    front=1,rear=1;
    memset(d,0x3f,sizeof(d));
    memset(p1,-1,sizeof(p1));
    memset(p2,-1,sizeof(p2));
    memset(vis,false,sizeof(vis));
    q[++rear]=src;vis[src]=true;d[src]=0;
    while(front<rear){
        int u=q[++front];vis[u]=false;
        for(int i=head[u];i!=-1;i=pre[i]){
            int v=ver[i];
            if(cap[i]<=0)continue;
            if(d[v]>d[u]+cost[i]){
                d[v]=d[u]+cost[i];
                p1[v]=u;p2[v]=i;
                if(!vis[v])vis[v]=true,q[++rear]=v;
            }
        }
    }
    if(p1[t]==-1)return false;
    int k=t;fs=0x3f3f3f3f3f3f3f3f;
    while(k!=s&&p1[k]!=-1)fs=min(fs,cap[p2[k]]),k=p1[k];
    if(fs<=0||k!=s)return false;
    k=t;cs=0;
    while(k!=s){
        cs=cs+cost[p2[k]];
        cap[p2[k]]-=fs;
        cap[p2[k]^1]+=fs;
        k=p1[k];
    }
    cs=cs*fs;return true;
}
void mincost_flow(int &fsum,int &csum){
    int ff,cc;
    fsum=0,csum=0;
    while(SPFA(s,ff,cc)){
        fsum=fsum+ff;
        csum=csum+cc;
    }
}
signed main(){
    memset(head,-1,sizeof(head));
    scanf("%lld%lld%lld%lld",&n,&k,&ms,&me);
    for(int i=1;i<=n;i++)scanf("%lld",&_s[i]);
    for(int i=1;i<=n;i++)scanf("%lld",&_e[i]);
    for(int i=1;i<=n;i++)sum+=_s[i],_e[i]-=_s[i];
    s=0,t=(n-k+1<<1|1)+1;
    for(int i=1;i<=n-k+1;i++)adde(i<<1|1,i<<1,inf,0);//zi
    for(int i=1;i<=n-k+1;i++)adde((i-1)<<1|1,i<<1,inf,0);//yi
    for(int i=1;i<=n-k;i++)adde(s,i<<1|1,k-ms-me,0);//C
    for(int i=1;i<=n-k+1;i++)adde(i<<1,t,k-ms-me,0);//C
    for(int i=1;i<=k;i++){id[i]=cnt+1;
        adde(min(i<<1|1,t-1),1,1,-_e[i]);
    }
    for(int i=1;i<=n-k;i++){id[i+k]=cnt+1;
        adde(min((i+k)<<1|1,t-1),i<<1|1,1,-_e[k+i]);
    }
    adde(1,t,me,0);adde(s,t-1,k-ms,0);
    int tmpf=0,tmps=0;mincost_flow(tmpf,tmps);sum-=tmps;
    printf("%lld\n",sum);
    for(int i=1;i<=n;i++)printf(cap[id[i]]?"S":"E");
    putchar('\n');
    return 0;
}

 

posted @ 2021-12-16 23:49  Remained_Apple  阅读(104)  评论(0)    收藏  举报