zoukankan      html  css  js  c++  java
  • hdu4719 Oh My Holy FFF 线段树维护dp

    题意:
    给你一个长度为n的数组v,你需要把这个数组分成很多段,你需要保证每一段的长度不能超过k
    我们设一共有m段,每一段右边界那个数为bi
    那么我们要使得sum(bi*bi-b(i-1))最大 (1<=i<=m,b0=0)
    你需要保证bi>b(i-1) (1<=i<=m)
    sum():表示求和

    题解:
    我们设数组下标从1开始
    dp[i]表示:对于v数组的前i个数的最大sum(bi*bi-b(i-1))为dp[i]
    dp转移方程:
    dp[i]=dp[j]+v[i]*v[i]-v[j] (i>j且v[i]>v[j])
    dp转移方程很容易找到,但是如果对于一个i,我们去寻找所有满足条件的j的话就该TLE了

    那么我们可以使用线段树进行维护,维护第i个位置的值为dp[i]-v[i]。这样的话对于一个j(j>i)
    我们只需要在线段树的[1,j-1]区间查找出来最大的值就可以了
    对于查找出来的值我们只需要加上v[j]*v[j]就是dp[j]的值(这一点很重要,可以说就是把维护的值改变了一下)

    但是我们发现题目还要求v[j]>v[i],怎么办呢,我们可以对所有vi排序,按照排过序之后顺序进行线段树维护查找更新
    就可以了



    代码:
    /*
    题意:
    给你一个长度为n的数组v,你需要把这个数组分成很多段,你需要保证每一段的长度不能超过k
    我们设一共有m段,每一段右边界那个数为bi
    那么我们要使得sum(bi*bi-b(i-1))最大  (1<=i<=m,b0=0)
    你需要保证bi>b(i-1) (1<=i<=m)
    sum():表示求和
    
    题解:
    我们设数组下标从1开始
    dp[i]表示:对于v数组的前i个数的最大sum(bi*bi-b(i-1))为dp[i]
    dp转移方程:
    dp[i]=dp[j]+v[i]*v[i]-v[j]  (i>j且v[i]>v[j])
    dp转移方程很容易找到,但是如果对于一个i,我们去寻找所有满足条件的j的话就该TLE了
    
    那么我们可以使用线段树进行维护,维护第i个位置的值为dp[i]-v[i]。这样的话对于一个j(j>i)
    我们只需要在线段树的[1,j-1]区间查找出来最大的值就可以了
    对于查找出来的值我们只需要加上v[j]*v[j]就是dp[j]的值(这一点很重要,可以说就是把维护的值改变了一下)
    
    但是我们发现题目还要求v[j]>v[i],怎么办呢,我们可以对所有vi排序,按照排过序之后顺序进行线段树维护查找更新
    就可以了
    */
    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+10;
    const int mod=20071027;
    const int INF=0x3f3f3f3f;
    ll tree[maxn<<2],dp[maxn];
    ll max(ll a,ll b)
    {
        if(a<b) return b;
        else return a;
    }
    void push_up(ll rt)
    {
        tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
    }
    void update(ll rt,ll L,ll R,ll pos,ll val)
    {
        if(L==R)
        {
            tree[rt]=val;
            return;
        }
        ll mid=(L+R)>>1;
        if(pos<=mid) update(rt<<1,L,mid,pos,val);
        else update(rt<<1|1,mid+1,R,pos,val);
        push_up(rt);
    }
    ll query(ll rt,ll L,ll R,ll LL,ll RR)
    {
        if(LL<=L && RR>=R)
        {
            return tree[rt];
        }
        ll mid=(L+R)>>1,ans=-1;
        if(LL<=mid) ans=max(ans,query(rt<<1,L,mid,LL,RR));
        if(RR>mid) ans=max(ans,query(rt<<1|1,mid+1,R,LL,RR));
        return ans;
    }
    struct shudui
    {
        ll val,id;
    }v[maxn],w[maxn];
    bool cmp(shudui x,shudui y)
    {
        return x.val<y.val;
    }
    int main()
    {
        ll t,p=0;
        scanf("%lld",&t);
        while(t--)
        {
            ll pos=0;
            memset(tree,-1,sizeof(tree));
            memset(dp,-1,sizeof(dp));
            ll n,k;
            scanf("%lld%lld",&n,&k);
            if(k==1)
            {
                for(ll i=1;i<=n;++i)
                    scanf("%lld",&v[i].val),v[i].id=i;
                ll res=v[1].val*v[1].val,flag=0;
                for(ll i=2;i<=n;++i)
                {
                    if(v[i].val>v[i-1].val)
                    {
                        res=(res+v[i].val*v[i].val)-v[i-1].val;
                    }
                    else
                    {
                        flag=1;
                        break;
                    }
                }
                if(flag==0)
                    printf("Case #%lld: %lld
    ",++p,res);
                else printf("Case #%lld: No solution
    ",++p);
                continue;
            }
            for(ll i=2;i<=n+1;++i)
                scanf("%lld",&v[i].val),v[i].id=i;
            update(1,1,n,1,0);
            dp[1]=v[1].val*v[1].val;
            ll tmp=dp[1]-v[1].val;
            sort(v+2,v+2+n,cmp);
            //printf("%lld**************
    ",query(1,1,n,3,4));
            for(ll i=2;i<=n+1;++i)
            {
                if(pos>0 && v[i].val!=v[i-1].val)
                {
                    //printf("%lld*******
    ",pos);
                    for(ll i=0;i<pos;++i)
                    {
                        update(1,1,n,w[i].id,w[i].val);
                    }
                    pos=0;
                }
                if(v[i].id==1)
                {
                    w[0].id=1;
                    w[0].val=tmp;
                    pos++;
                    continue;
                }
                ll ans=query(1,1,n,max(1,v[i].id-k),v[i].id-1);
                //printf("%lld %lld*****
    ",ans,v[i].id);
                if(ans!=-1)
                {
                    w[pos].id=v[i].id;
                    w[pos].val=(ans+v[i].val*v[i].val)-v[i].val;
                    dp[v[i].id]=max(w[pos].val+v[i].val,dp[v[i].id]);
                    pos++;
                }
            }
            if(dp[n+1]!=-1)
            printf("Case #%lld: %lld
    ",++p,dp[n+1]);
            else printf("Case #%lld: No solution
    ",++p);
        }
        return 0;
    }
  • 相关阅读:
    判断分流使用
    Mac系统如何显示隐藏文件?
    Brew安装的软件查询安装位置
    JetBrains 产品线破解方法
    Linux查看与挂载新磁盘
    对BRD、MRD、PRD、FSD四类产品文档的理解
    网站收藏
    收藏
    官方文档
    java 的访问权限控制
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13973944.html
Copyright © 2011-2022 走看看