首页 > 其他 > 详细

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

时间:2019-01-12 22:20:54      阅读:39      评论:0      收藏:0      [点我收藏+]

标签:dot   head   emp   可能   pac   我们   方程   rotate   ima   

题目描述:

技术分享图片

样例:

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:令\(dp(i,j)\)表示前\(i\)个点选\(j\)个,能得到的最大价值。

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

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

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

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

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

技术分享图片

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

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

复杂度\(O(n\log 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,平衡树]

标签:dot   head   emp   可能   pac   我们   方程   rotate   ima   

原文:https://www.cnblogs.com/p-b-p-b/p/10261047.html

(0)
(0)
   
举报
评论 一句话评论(0
0条  
登录后才能评论!
© 2014 bubuko.com 版权所有 鲁ICP备09046678号-4
打开技术之扣,分享程序人生!
             

鲁公网安备 37021202000002号