zoukankan      html  css  js  c++  java
  • HDU 5773 The All-purpose Zero

    题目:The All-purpose Zero

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=5773

    题意:给一个大小为n的数组a[],包含0到100万的数字,0可以当作任意整数,要求输出最长单调递增子序列的长度。(子序列可以跳着选,子序列必须严格递增)

    思路:

      动态规划+二分+线段树。比赛时候想出来的解法就是这个了,结果看别人的解法简直简单粗暴,学到了。

      动态规划+二分在nlogn时间里面找出普通的(也就是不包含0)的解,线段树处理含0的情况。

      dp[i]表示长度为i 的子序列末尾最小是几。令maxt为当前最大的长度,初始为0,dp[0]=-100010,然后i 从1遍历到n,每次都从dp[0]到dp[maxt]里面找出序列长度最大的且末尾小于a[i]的位置pos(这里要用到二分,注意这里的dp数组肯定是有序的),如果pos+1大于maxt,更新maxt,如果没有则判断dp[pos+1]和a[i]的大小,如果a[i]小就更新dp[pos+1]。

      遇到0的时候,因为0可以当作任意数,所以每个dp[i]后面都可以接个比dp[i]大1的数,因为所有子序列长度+1,所以我们不移动dp[i],而是给另外的一个变量cha++,最终cha+maxt就是答案。有了cha,我们还是要给所有的dp[i]+1,这里可以用到线段树,区间更新,单点取值。

    AC代码:

      1 #include<stdio.h>
      2 int min(int a,int b)
      3 {
      4   return a<b?a:b;
      5 }
      6 struct Node
      7 {
      8   int w;
      9   int add;
     10   int l,r;
     11   int mid()
     12   {
     13     return (l+r)/2;
     14   }
     15 };
     16 Node v[400040];
     17 void build(int l,int r,int rt)
     18 {
     19   v[rt].w=0;
     20   v[rt].add=0;
     21   v[rt].l=l;
     22   v[rt].r=r;
     23   if(l==r) return ;
     24   build(l,v[rt].mid(),rt<<1);
     25   build(v[rt].mid()+1,r,rt<<1|1);
     26 }
     27 void fu(int pos,int val,int rt)
     28 {
     29   if(v[rt].l==v[rt].r)
     30   {
     31     v[rt].w=val;
     32     v[rt].add=0;
     33     return ;
     34   }
     35   if(v[rt].add>0)
     36   {
     37     v[rt<<1].add+=v[rt].add;
     38     v[rt<<1|1].add+=v[rt].add;
     39     v[rt].add=0;
     40   }
     41   int mid=v[rt].mid();
     42   if(pos<=mid) return fu(pos,val,rt<<1);
     43   else return fu(pos,val,rt<<1|1);
     44 }
     45 void update(int l,int r,int rt)
     46 {
     47   if(v[rt].l==l&&v[rt].r==r)
     48   {
     49     v[rt].add++;
     50     return ;
     51   }
     52   int mid=v[rt].mid();
     53   if(l>mid)
     54     update(l,r,rt<<1|1);
     55   else if(r<=mid) update(l,r,rt<<1);
     56   else
     57   {
     58     update(l,mid,rt<<1);
     59     update(mid+1,r,rt<<1|1);
     60   }
     61 }
     62 int look(int pos,int rt)
     63 {
     64   if(v[rt].l==v[rt].r)
     65   {
     66     v[rt].w+=v[rt].add;
     67     v[rt].add=0;
     68     return v[rt].w;
     69   }
     70   if(v[rt].add>0)
     71   {
     72     v[rt<<1].add+=v[rt].add;
     73     v[rt<<1|1].add+=v[rt].add;
     74     v[rt].add=0;
     75   }
     76   int mid=v[rt].mid();
     77   if(pos<=mid) return look(pos,rt<<1);
     78   else return look(pos,rt<<1|1);
     79 }
     80 int er(int l,int r,int x)
     81 {
     82   while(l<r)
     83   {
     84     int mid=(l+r+1)>>1;
     85     if(look(mid,1)>=x) r=mid-1;
     86     else l=mid;
     87   }
     88   return l;
     89 }
     90 int a[100010];
     91 int main()
     92 {
     93   int t,n,cas=1;
     94   scanf("%d",&t);
     95   while(t--)
     96   {
     97     scanf("%d",&n);
     98     for(int i=1;i<=n;i++)
     99     {
    100       scanf("%d",a+i);
    101     }
    102     build(0,n,1);
    103     int maxt=0,cha=0;
    104     fu(0,-100010,1);
    105     for(int i=1;i<=n;i++)
    106     {
    107       if(a[i]==0)
    108       {
    109         cha++;
    110         update(0,i,1);
    111         continue;
    112       }
    113       int pos=er(0,maxt,a[i]);
    114       if(pos==maxt)
    115       {
    116         maxt++;
    117         fu(maxt,a[i],1);
    118       }
    119       else
    120       {
    121         fu(pos+1,min(look(pos+1,1),a[i]),1);
    122       }
    123     }
    124     printf("Case #%d: %d
    ",cas++,maxt+cha);
    125   }
    126   return 0;
    127 }
  • 相关阅读:
    Oracle Golden Gate
    DNS
    RMAN 管理
    黄伟-RAC生产库现场调整本分策略实战
    Linux下RAID技术
    OCP之黄伟 2
    About NULL Value
    OCP之黄伟
    Table
    Perl的简单变量
  • 原文地址:https://www.cnblogs.com/hchlqlz-oj-mrj/p/5715818.html
Copyright © 2011-2022 走看看