zoukankan      html  css  js  c++  java
  • dp+树状数组(最长上升子序列+树状数组)

    There are N flowers arranged in a row. For each i (1iN), the height and the beauty of the i-th flower from the left is hihi and aiai, respectively. Here, h1,h2,,hN are all distinct.

    Taro is pulling out some flowers so that the following condition is met:

    • The heights of the remaining flowers are monotonically increasing from left to right.

    Find the maximum possible sum of the beauties of the remaining flowers.

    Constraints

     

    • All values in input are integers.
    • 1N2×1e5
    • 1hiN
    • h1,h2,,hN are all distinct.
    • 1ai1e9

    Input

     

    Input is given from Standard Input in the following format:

    NN
    h1 h2  hN
    a1 a2  aN
    

    Output

     

    Print the maximum possible sum of the beauties of the remaining flowers.

    Sample Input 1

     

    4
    3 1 4 2
    10 20 30 40
    

    Sample Output 1

     

    60
    

    We should keep the second and fourth flowers from the left. Then, the heights would be 1,21,2 from left to right, which is monotonically increasing, and the sum of the beauties would be 20+40=6020+40=60.

    Sample Input 2

     

    1
    1
    10
    

    Sample Output 2

     

    10
    

    The condition is met already at the beginning.

    Sample Input 3

     

    5
    1 2 3 4 5
    1000000000 1000000000 1000000000 1000000000 1000000000
    

    Sample Output 3

     

    5000000000
    

    The answer may not fit into a 32-bit integer type.

    Sample Input 4

     

    9
    4 2 5 8 3 6 1 7 9
    6 8 8 4 6 3 5 7 5
    

    Sample Output 4

     

    31
    

    We should keep the second, third, sixth, eighth and ninth flowers from the left.

    题意:

    给你 h数组和s数组
    问你 h数组一直上升的序列中 s数组最大的和是多少

    这个题就是dp[i]代表的是前i朵花,并且取第i朵的最大和,那么转移方程就是dp[i]=dp[j]+v[i](j<i,a[j]<a[i])

    注意这个答案不是dp[n]而是max(dp[1],dp[2],dp[3]........)

    然后如果你普通的写就是:

    for(int i = 1;i<=n;++i)
        {
            for(int j = 1;j<i;++j)
            {
                if(h[i]>h[j])
                {
                    dp[i] = max(dp[i],dp[j]+arr[i]);
                    ans = max(ans,dp[i]);
                }
            }
       }

    这样肯定会超时的,所以你可以用线段树或者树状数组来维护1到i-1的dp数组的最大值

    线段树:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    typedef long long ll; 
    using namespace std;
    int n;
    const int maxn=5e6+100;
    ll h[maxn];
    ll a[maxn];
    ll dp[maxn];//dp[i]为前i个的最大值 
    struct node{
        int l,r;
        ll ma;
    }t[maxn];
    void build(int p,int l,int r){
        t[p].l=l;
        t[p].r=r;
        if(l==r){
            return ;
        }
        int mid=(t[p].l+t[p].r)/2;
        build(2*p,l,mid);
        build(2*p+1,mid+1,r);
    }
    void update(int p,int x,ll k){
        if(t[p].r==t[p].l){
            t[p].ma=k;
            return ;
        }
        int mid=(t[p].l+t[p].r)/2;
        if(x<=mid){
            update(2*p,x,k);
        }
        else{
            update(2*p+1,x,k);
        }
        t[p].ma=max(t[2*p].ma,t[2*p+1].ma);
    } 
    ll query(int p,int l,int r){
        if(l<=t[p].l&&r>=t[p].r){
            return t[p].ma;
        }
        ll ans=-1e18;
        int mid=(t[p].l+t[p].r)/2;
        if(l<=mid){
            ans=max(ans,query(2*p,l,r));
        } 
        if(r>mid){
            ans=max(ans,query(2*p+1,l,r));
        } 
        return ans;
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>h[i]; 
        }
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        build(1,1,2e5+10);
        ll ma=0; 
        for(int i=1;i<=n;i++){
            ll z=query(1,1,h[i]); 
            dp[i]=(1ll)*(z+a[i]);
            update(1,h[i],dp[i]);
            ma=max(ma,dp[i]);
        }
        cout<<ma<<endl;
    } 
    /*
    4
    1 2 3 2 3
    1 1 1 2 3
    */

    树状数组:

    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll; 
    const int maxn=1e6+100;
    ll dp[maxn];
    int h[maxn];
    ll a[maxn];
    ll ans[maxn];
    int n;
    ll lowbit(int x){
        return x&-x;
    }
    void add(int x,ll k){
        for(int i=x;i<=n;i+=lowbit(i)){
            ans[i]=max(ans[i],k);
        } 
    }
    ll query(int x){
        ll z=0;
        for(int i=x;i>0;i-=lowbit(i)){
            z=max(z,ans[i]);
        } 
        return z;
    } 
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>h[i];
        }
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        ll ma=0;
        for(int i=1;i<=n;i++){
            dp[i]=a[i]+query(h[i]);
            ma=max(ma,dp[i]);
            add(h[i],dp[i]); 
        }
        cout<<ma<<endl;
    }
  • 相关阅读:
    神不在的星期天
    炸弹问题——一种会引发死锁的情景模式
    JavaScript的类和继承
    没有功劳也有苦劳
    使用http代理服务器解决本地客户端页面的跨域AJAX问题
    04数组 字符数组
    01 数据类型 、常量变量、运算符、表达式、格式化输入输出
    03循环结构
    .NET编译、WOW64注册表访问、同时在X86和X64平台上部署应用程序
    Vistual Studio 2008中的智能感应功能
  • 原文地址:https://www.cnblogs.com/lipu123/p/14515182.html
Copyright © 2011-2022 走看看