2019雅礼集训 D7T2 subsequence [DP,平衡树]

Posted p-b-p-b

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019雅礼集训 D7T2 subsequence [DP,平衡树]相关的知识,希望对你有一定的参考价值。

题目描述:

技术分享图片

样例:

input1:
5
-2 -8 0 5 -3

output1:
5 10 13 2 -13

input2:
6
-10 20 -30 40 -50 60

output2:
60 160 280 390 400 210

数据范围与约定:

技术分享图片


考虑DP:令(dp(i,j))表示前(i)个点选(j)个,能得到的最大价值。

得到转移方程:(dp(i,j)=max{dp(i-1,j),dp(i-1,j-1)+a_icdot j})

这个方程很明显是(n^2)的。

经过打表/分析样例/严谨证明(不可能的),可以发现结论:(i)相同时,转移方程中满足后一种决策
更优的(j)一定是一段后缀 。

(人话:只要求(dp(i,j_0))时选了(a_i),那么对于所有(jgeq j_0),都会选择(a_i)

证明嘛,我看不懂,就直接复制上来啦

技术分享图片

考虑选择后一个决策的条件:(dp(i-1,j-1)+a_icdot j geq dp(i-1,j)),即(a_icdot jgeq dp(i-1,j)-dp(i-1,j-1))

于是我们可以用一棵平衡树来维护(dp(i-1,j)-dp(i-1,j-1)?)(即它的差分),在上面二分出(j_0?)后就可以插入这个位置并对后缀进行区间加了(本来是区间加上一个等差序列,但这里已经差分过了,就可以普通区间加了)。

复杂度(O(nlog n)),代码很短。

#include<bits/stdc++.h>
namespace my_std{
    using namespace std;
    #define mod 998244353
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define sz 200010
    typedef long long ll;
    template<typename T>
    inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();
        double d=0.1;
        while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar();
        while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar();
        if(ch==‘.‘)
        {
            ch=getchar();
            while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar();
        }
        t=(f?-t:t);
    }
    template<typename T,typename... Args>
    inline void read(T& t,Args&... args){read(t); read(args...);}
    void file(){freopen("a.txt","r",stdin);}
    inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

namespace Splay
{
    ll w[sz],tag[sz];
    int fa[sz],ch[sz][2],size[sz],root,cnt;
    #define ls ch[x][0]
    #define rs ch[x][1]
    
    void Add(int x,ll t){w[x]+=t;tag[x]+=t;}
    void pushdown(int x){ ll &t=tag[x]; if (t) { Add(ls,t); Add(rs,t); } t=0; }
    void pushup(int x){size[x]=size[ls]+size[rs]+1;}
    bool get(int x){return ch[fa[x]][1]==x;}
    
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=get(x),w=ch[x][!k];
        if (z) pushdown(z);pushdown(y);pushdown(x);
        if (z) ch[z][get(y)]=x;ch[x][!k]=y;ch[y][k]=w;
        if (w) fa[w]=y;fa[y]=x;fa[x]=z;
        pushup(y);pushup(x);
    }
    void splay(int x)
    {
        while (fa[x])
        {
            int y=fa[x];
            if (fa[y]) rotate(get(x)==get(y)?y:x);
            rotate(x);
        }
        root=x;
    }
    void insert(int &x,int f,ll cur,ll v)
    {
        if (!x)
        {
            x=++cnt;
            fa[x]=f;size[x]=1;w[x]=(cur+1)*v;
            return splay(x);
        }
        pushdown(x);
        int siz=cur+1+size[ls];
        if (w[x]>=v*siz) insert(rs,x,siz,v);
        else insert(ls,x,cur,v);
    }
    void getans(int x,ll &cur)
    {
        pushdown(x);
        if (ls) getans(ls,cur);
        printf("%lld ",cur+=w[x]);
        if (rs) getans(rs,cur);
    }
    #undef ls
    #undef rs
}
using namespace Splay;


int n;
ll a[sz];

int main()
{
    file();
    read(n);
    rep(i,1,n) read(a[i]);
    rep(i,1,n)
    {
        insert(root,0,0,a[i]);
        if (ch[root][1]) Add(ch[root][1],a[i]);
    }
    ll ans=0;
    getans(root,ans);
}

以上是关于2019雅礼集训 D7T2 subsequence [DP,平衡树]的主要内容,如果未能解决你的问题,请参考以下文章

2019雅礼集训 D8T1 union [咕咕咕]

2019雅礼集训 D10T2 硬币翻转 [交互题]

2019雅礼集训 D11T3 字符串 [交互题]

2019雅礼集训 D4T1 w [费用流]

2019雅礼集训 D10T1 数字重排 [DP]

2019雅礼集训 D8T3 union [主席树]