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;
    }
  • 相关阅读:
    HDU5976 Detachment (预处理前缀和+贪心+逆元)
    FJUT OJ 2584 QAQ的变强魔咒(KMP)
    HDU1867 A + B for you again(KMP)
    POJ 1469 COURSES(二分图模板题)
    HihoCoder
    HDU 3336 Count the string (基础KMP)
    POJ2185 Milking Grid(KMP)
    144.链表库以及迭代算法原理
    143.vector模板库
    152.字符串模板库
  • 原文地址:https://www.cnblogs.com/lipu123/p/14515182.html
Copyright © 2011-2022 走看看