zoukankan      html  css  js  c++  java
  • BZOJ 2442 Usaco2011 Open 修建草坪

    2442: [Usaco2011 Open]修剪草坪

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1159  Solved: 593
    [Submit][Status][Discuss]

    Description


    在一年前赢得了小镇的最佳草坪比赛后,FJ变得很懒,再也没有修剪过草坪。现在,
    新一轮的最佳草坪比赛又开始了,FJ希望能够再次夺冠。

    然而,FJ的草坪非常脏乱,因此,FJ只能够让他的奶牛来完成这项工作。FJ有N
    (1 <= N <= 100,000)只排成一排的奶牛,编号为1...N。每只奶牛的效率是不同的,
    奶牛i的效率为E_i(0 <= E_i <= 1,000,000,000)。

    靠近的奶牛们很熟悉,因此,如果FJ安排超过K只连续的奶牛,那么,这些奶牛就会罢工
    去开派对:)。因此,现在FJ需要你的帮助,计算FJ可以得到的最大效率,并且该方案中
    没有连续的超过K只奶牛。

    Input

    * 第一行:空格隔开的两个整数N和K

    * 第二到N+1行:第i+1行有一个整数E_i

    Output

    * 第一行:一个值,表示FJ可以得到的最大的效率值。

    Sample Input

    5 2
    1
    2
    3
    4
    5

    输入解释:

    FJ有5只奶牛,他们的效率为1,2,3,4,5。他们希望选取效率总和最大的奶牛,但是
    他不能选取超过2只连续的奶牛

    Sample Output

    12

    FJ可以选择出了第三只以外的其他奶牛,总的效率为1+2+4+5=12。

    HINT

    Source

    这道题是个dp不难想

    首先预处理出来前缀和sum数组

    我们列出状态转移方程

    用f[i]来表示在前i头奶牛中要第i头奶牛能获得最大的效率是多少

    枚举j,强制第j头奶牛不选,那么f[i]=max(f[i],f[j-1]-sum[j]+sum[i]);

    j的范围是i-k+1到i-1,复杂度最坏是n^2

    把原方程分解我们发现只和f[j-1]-sum[j]有关

    我们可以像之前一样用一个线段树之类的去维护

    也可以用单调队列去维护f[j-1]-sum[j]

    线段树有可能会被卡QAQ

    还是单调队列大法好啊    O(n)

    细节上的处理还是和之前的题目一样

    具体参考代码:

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x=0;ll f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const ll MAXN=1e6+10;
    namespace zhangenming{
        ll f[MAXN],n,k,a[MAXN],sum[MAXN],q[MAXN],head=1,tail=0;
        void init(){
            n=read();k=read();
            memset(sum,0,sizeof(sum));
            for(ll i=1;i<=n;i++){
                a[i]=read();
                sum[i]=sum[i-1]+a[i];
            }
        }
        void solve(){
            memset(f,0,sizeof(f));
            for(ll i=1;i<=k;i++){
                f[i]=sum[i];
                ll tn=f[i-1]-sum[i];
                while(head<=tail&&tn>f[q[tail]-1]-sum[q[tail]]) tail--;
                q[++tail]=i;
                //cout<<i<<' '<<f[i]<<' '<<tn<<endl;
            }
            for(ll i=k+1;i<=n;i++){
                while(i-q[head]>k) head++;
                //cout<<i<<' '<<q[head]<<' '<<f[q[head]-1]-sum[q[head]]<<' ';
                f[i]=f[q[head]-1]-sum[q[head]]+sum[i];
                ll tn=f[i-1]-sum[i];
                //cout<<tn<<' ';
                while(tail>=head&&tn>f[q[tail]-1]-sum[q[tail]]) tail--;
                q[++tail]=i;
                //cout<<f[i]<<endl;
            }
            ll maxn=-1000000;
            for(ll i=1;i<=n;i++){
                maxn=max(maxn,f[i]);
            }
            cout<<maxn<<endl;
            //cout<<f[n]<<endl;
        }
    }
    int main(){
        using namespace zhangenming;
        init();
        solve();
        return 0;
    }#include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x=0;ll f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const ll MAXN=1e6+10;
    namespace zhangenming{
        ll f[MAXN],n,k,a[MAXN],sum[MAXN],q[MAXN],head=1,tail=0;
        void init(){
            n=read();k=read();
            memset(sum,0,sizeof(sum));
            for(ll i=1;i<=n;i++){
                a[i]=read();
                sum[i]=sum[i-1]+a[i];
            }
        }
        void solve(){
            memset(f,0,sizeof(f));
            for(ll i=1;i<=k;i++){
                f[i]=sum[i];
                ll tn=f[i-1]-sum[i];
                while(head<=tail&&tn>f[q[tail]-1]-sum[q[tail]]) tail--;
                q[++tail]=i;
                //cout<<i<<' '<<f[i]<<' '<<tn<<endl;
            }
            for(ll i=k+1;i<=n;i++){
                while(i-q[head]>k) head++;
                //cout<<i<<' '<<q[head]<<' '<<f[q[head]-1]-sum[q[head]]<<' ';
                f[i]=f[q[head]-1]-sum[q[head]]+sum[i];
                ll tn=f[i-1]-sum[i];
                //cout<<tn<<' ';
                while(tail>=head&&tn>f[q[tail]-1]-sum[q[tail]]) tail--;
                q[++tail]=i;
                //cout<<f[i]<<endl;
            }
            ll maxn=-1000000;
            for(ll i=1;i<=n;i++){
                maxn=max(maxn,f[i]);
            }
            cout<<maxn<<endl;
            //cout<<f[n]<<endl;
        }
    }
    int main(){
        using namespace zhangenming;
        init();
        solve();
        return 0;
    }

    有一个失误的地方

    最后其实可以不用求maxn,因为随着i的增加,f[i]会不严格单调递增,直接输出f[n]即可

    注意过程中的变量要开long long

    网上还有一些别的思路

    就是把能获得最高多少效率转化为最少失去多少效率

    接下来的步骤也是一样的只不过用单调队列或线段树去维护的值不一样了

    代码这里就不给出了

  • 相关阅读:
    变量按数据类型分类
    构造方法重载 及注意事项
    构造方法-带参
    构造方法-无参
    对对象中的属性赋值(两种方法)
    局部变量的值赋给成员变量 案例(红色字体)
    成员变量与局部变量区别
    创建对象综合案例
    20151015css3 部分css2的内容
    20151012jq4
  • 原文地址:https://www.cnblogs.com/something-for-nothing/p/7809108.html
Copyright © 2011-2022 走看看