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;
    }
  • 相关阅读:
    记忆碎片:我的2007
    查看 Oracle 是用spfile 启动还是 pfile 启动
    Oracle 10g OCP 042 题库 71120 题 共168题
    Oracle OLAP 与 OLTP 介绍
    Oracle Data Guard Switchover 切换
    Linux 终端访问 FTP 及 上传下载 文件
    多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
    Oracle 表连接方式(内连接/外连接/自连接) 详解
    Oracle 表连接方式(内连接/外连接/自连接) 详解
    查看 Oracle 是用spfile 启动还是 pfile 启动
  • 原文地址:https://www.cnblogs.com/lipu123/p/14515182.html
Copyright © 2011-2022 走看看