• BZOJ2151 种树(贪心+堆+链表/wqs二分+动态规划)


      dp容易想到,但没法进一步优化了。

      考虑贪心,每次选出价值最大的物品。但这显然是不对的因为会影响其他物品的选择。

      于是考虑加上反悔操作。每次选出一个物品后,将其相邻两物品删除,再将原物品价值变为相邻两物品价值和-原物品价值。这样如果再次选择该物品就可以达到改为选择相邻两物品的效果。并且最优方案中相邻两物品一定要么都选要么都不选,否则不如选择原物品。

      这种带反悔的贪心策略似乎类似地在网络流算法中出现,应该是一个比较普遍的做法,然而并不会证。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 200010
    int n,m,a[N],pre[N],nxt[N],ans;
    bool flag[N];
    struct data
    {
        int i,x;
        bool operator <(const data&a) const
        {
            return x<a.x;
        }
    };
    priority_queue<data> q;
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2151.in","r",stdin);
        freopen("bzoj2151.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        if (m>n/2) {cout<<"Error!";return 0;}
        for (int i=1;i<=n;i++) a[i]=read(),q.push((data){i,a[i]});
        for (int i=1;i<n;i++) nxt[i]=i+1;
        for (int i=2;i<=n;i++) pre[i]=i-1;
        pre[1]=n,nxt[n]=1;
        for (int i=1;i<=m;i++)
        {
            while (flag[q.top().i]) q.pop();
            data t=q.top();q.pop();
            ans+=t.x;
            int x=pre[t.i],y=nxt[t.i];
            a[t.i]=a[x]+a[y]-a[t.i];
            q.push((data){t.i,a[t.i]});
            flag[x]=flag[y]=1;
            nxt[pre[x]]=t.i,pre[t.i]=pre[x];
            pre[nxt[y]]=t.i,nxt[t.i]=nxt[y];
        }
        cout<<ans;
        return 0;
    }

       不过dp真的没救了吗?看到这个恰好选k个非常容易让人联想到wqs二分。于是二分多选一个数的代价,跑正常的dp,就过掉了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 200010
    #define inf 2000000010
    int n,m,a[N],f[N][2][2],g[N][2][2],ans;
    void chkmax(int &x,int &y,int a,int b)
    {
        if (a>x||a==x&&b<y) x=a,y=b;
    }
    bool check(int k)
    {
        memset(f,0,sizeof(f)),memset(g,0,sizeof(g));
        f[1][1][1]=a[1]+k,g[1][1][1]=1;
        f[1][1][0]=f[1][0][1]=-inf;
        for (int i=2;i<=n;i++)
        {
            f[i][1][0]=f[i-1][0][0]+a[i]+k,g[i][1][0]=g[i-1][0][0]+1;
            if (i<n) f[i][1][1]=f[i-1][0][1]+a[i]+k,g[i][1][1]=g[i-1][0][1]+1;
            if (f[i-1][0][0]>f[i-1][1][0]||f[i-1][0][0]==f[i-1][1][0]&&g[i-1][0][0]<g[i-1][1][0]) f[i][0][0]=f[i-1][0][0],g[i][0][0]=g[i-1][0][0];
            else f[i][0][0]=f[i-1][1][0],g[i][0][0]=g[i-1][1][0];
            if (f[i-1][0][1]>f[i-1][1][1]||f[i-1][0][1]==f[i-1][1][1]&&g[i-1][0][1]<g[i-1][1][1]) f[i][0][1]=f[i-1][0][1],g[i][0][1]=g[i-1][0][1];
            else f[i][0][1]=f[i-1][1][1],g[i][0][1]=g[i-1][1][1];
        }
        int x=f[n][0][0],y=g[n][0][0];
        chkmax(x,y,f[n][0][1],g[n][0][1]);
        chkmax(x,y,f[n][1][1],g[n][1][1]);
        chkmax(x,y,f[n][1][0],g[n][1][0]);
        if (y<=m) {ans=x-m*k;return 1;}
        else return 0;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("force.in","r",stdin);
        freopen("force.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        if (m>n/2) {cout<<"Error!";return 0;}
        for (int i=1;i<=n;i++) a[i]=read();
        int l=-1001,r=1001;
        while (l<=r)
        {
            int mid=(l+r)/2;
            if (check(mid)) l=mid+1;
            else r=mid-1;
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    java 正则 二次转义
    HDU1789 Doing Homework again 【贪心】
    扣丁学堂笔记第22天多媒体播放
    [Python]BeautifulSoup—HTML解析包
    Android高级控件(三)——&#160;使用Google ZXing实现二维码的扫描和生成相关功能体系
    Business Process and SAP ERP
    HTML基础知识总结一
    控制器View是怎样创建的?
    cocos2d-x 3.0 场景切换特效汇总
    LeetCode 3Sum
  • 原文地址:https://www.cnblogs.com/Gloid/p/9800542.html
Copyright © 2020-2023  润新知