hdu 3564 线段树+dp
实在惭愧。。。理解错了题意还A了。。
题意:现在第i个数字表示i这个数字放在第几个位置上面,如果这个位置上面已经有数字则向后移动。
一开始我以为是先将所有的数字放好位子之后+二分最长上升就可以,但是思路错了,真正应该记录的值是i这个数字存放在哪个位子,我们在保证数字一定上升的基础上,来求位子的上升。因为第一个数字放的是1,第二个为2,这样的话我们就能求出每次放一个数字产生的最上升序列长度了。。
View Code
1 #include<iostream> 2 #include<stdio.h> 3 #include<stdlib.h> 4 const int N = 100005; 5 int Pos[N],num[N],len[N<<2]; 6 void build(int t,int l,int r) 7 { 8 len[t]=r-l+1; 9 if(l==r)return ; 10 int m=(l+r)>>1; 11 build(t<<1,l,m); 12 build(t<<1|1,m+1,r); 13 } 14 void update(int t,int l,int r,int v,int i) 15 { 16 len[t]--; 17 if(l==r) 18 { 19 Pos[i]=l; 20 return ; 21 } 22 int m=(r+l)>>1; 23 if(len[t<<1]>=v)update(t<<1,l,m,v,i); 24 else update(t<<1|1,m+1,r,v-len[t<<1],i); 25 } 26 int F_pos(int k,int len) 27 { 28 int l=1,r=len; 29 while(l<=r) 30 { 31 int m=(l+r)>>1; 32 if(num[m]<k)l=m+1; 33 else r=m-1; 34 } 35 return l; 36 } 37 int main() 38 { 39 int t,n,top,T=0; 40 scanf("%d",&t); 41 while(t--) 42 { 43 scanf("%d",&n); 44 build(1,1,n); 45 for(int i=1;i<=n;i++) 46 { 47 scanf("%d",&num[i]); 48 num[i]++; 49 }; 50 for(int i=n;i>=1;i--) 51 { 52 update(1,1,n,num[i],i); 53 } 54 top=0; 55 printf("Case #%d:\n",++T); 56 for(int i=1;i<=n;i++) 57 { 58 if(top==0||Pos[i]>num[top]) 59 num[++top]=Pos[i]; 60 else 61 { 62 int f=F_pos(Pos[i],top); 63 num[f]=Pos[i]; 64 } 65 printf("%d\n",top); 66 } 67 printf("\n"); 68 } 69 return 0; 70 }