• hdu5125 树状数组+dp


     hdu5125 他说的是n个人每个人都有两个气球a,b,气球各自都有相应的体积,现在让他们按照序号排列好来,对他们的a气球体积值计算最长上升子序列,对于这整个排列来说有m次机会让你将a气球替换成b气球(允许不使用完),问最后的最长上升子序列 的长度是多少,哈哈,当然用dp的思想我们很容易就能知道状态的转移 dp[1000][1000][2],但是苦于状态转移的复杂度太大了达到了 n*n*m肯定受不了,那好我们可以列出这个方程的转移方法
    (0表示a气球1为b气球)
    dp[i][j][0]=max(  dp[k][j][0]     +1(a[k]<a[i]) , dp[k][j][j]     +1(b[k]<a[i]) )0<=k<i 
    dp[i][j][1]=max(  dp[k][j-1][0] +1(a[k]<b[i]) , dp[k][j-1][1] +1(b[k]<b[i])  )0<=k<i
    想想优化方法 看来还是需要有换个想法的能力 啊 !
    通过建立m棵树状数组 第j棵树 表示 使用了 j 个 能 量 的 时 候 每个位置所能到达的最高点,说清楚一点就是讲这n*2个气球体积进行离散,得到了树状数组的每个节点从第0个人枚举到第n-1个,比如到达了第i个人 那么 到达他时使用了j个机会的 方案是不是 就是去找比ai(假设离散后在k这个位置)小的那些气球使用j个机会时达到的最长序列加1呢,好那么现就使用树状数组去计算出前k-1 项的 最大值S,然后将S这个值插入当前这个树状数组中 ,那么现在 我们考虑使用b气球可以去j-1 这棵树上去找 然后得到的值加1 插入第j棵树上,哇这样很完美啊! 瞬间将复杂度减了2个0,这样一直不断地做下去直到结束.
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <string.h>
    using namespace std;
    const int maxn=1005;
    int a[maxn],b[maxn];
    int c[maxn][maxn*2],h[maxn*2],L;
    int lowbit(int x){
     return x&(-x);
    }
    void add(int loc, int floor,int v){
          while(loc<=L){
             c[floor][loc]=max(v,c[floor][loc]);
             loc+=lowbit(loc);
          }
    }
    int sum(int loc, int floor){
         int ans=0;
         while(loc>0){
             ans=max(c[floor][loc],ans);
             loc-=lowbit(loc);
         }
         return ans;
    }
    
    int main()
    {
        int cas;
        scanf("%d",&cas);
        while(cas--){
             int n,m;
             scanf("%d%d",&n,&m);
             L=0;
             for(int i=0; i<n; ++i){
                scanf("%d%d",&a[i],&b[i]);
                h[L++]=a[i]; h[L++]=b[i];
             }
             memset(c,0,sizeof(c));
             sort(h,h+L);
             L=unique(h,h+L)-h;
             int ans=1;
             for(int i=0; i<n; ++i){
                int loca = lower_bound(h,h+L,a[i])-h+1;
                int locb = lower_bound(h,h+L,b[i])-h+1;
                int val;
                for(int j=min(i+1,m);j>0; j--){
                       val = sum(loca-1,j);
                       ans=max(ans,val+1);
                      add(loca,j,val+1);
                        val = sum(locb-1,j-1);
                       ans=max(ans,val+1);
                    add(locb,j,val+1);
                }
                     val = sum(loca-1,0);
                     ans=max(ans,val+1);
                    add(loca,0,val+1);
             }
             printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【大数据学习与分享】技术干货合集
    K8S集群搭建
    字节跳动面试难吗,应该如何应对?(含内推方式)
    我的新书《C++服务器开发精髓》终于出版啦
    同事内推的那位Linux C/C++后端开发同学面试没过......
    死磕hyperledger fabric源码|Order节点概述
    死磕以太坊源码分析之EVM如何调用ABI编码的外部方法
    死磕以太坊源码分析之EVM动态数据类型
    死磕以太坊源码分析之EVM固定长度数据类型表示
    死磕以太坊源码分析之EVM指令集
  • 原文地址:https://www.cnblogs.com/Opaser/p/4160740.html
Copyright © 2020-2023  润新知