题意:在一个序列中找出最长的某个序列。找出的序列满足题中的条件。
关键:对于 第 i 个位置上的数,要知道与之相隔至少d的位置上的数的大小。可以利用线段树进行统计,查询。更新的时候利用dp的思想。
1 /* 2 统计某一段内有多少比aim小的数据 3 在更新的时候利用了dp的思想。 4 */ 5 #include<stdio.h> 6 #include<string.h> 7 #include<stdlib.h> 8 #include<algorithm> 9 using namespace std; 10 const int maxn = 100005; 11 struct node{ 12 int sum,l,r; 13 }anode[ maxn<<2 ]; 14 #define left( x ) (x<<1) 15 #define right( x ) ((x<<1)+1) 16 17 int data[ maxn ],dp[ maxn ]; 18 19 void build( int l,int r,int n ){ 20 anode[ n ].l = l; 21 anode[ n ].r = r; 22 anode[ n ].sum = 0; 23 if( l==r ) return ; 24 int mid = (l+r)/2; 25 build( l,mid,left( n ) ); 26 build( mid+1,r,right( n ) ); 27 return ; 28 } 29 30 void update( int aim_pos,int aim_value,int l,int r,int n ){ 31 if( l==r ){ 32 anode[ n ].sum = aim_value; 33 return ; 34 } 35 int mid = (l+r)/2; 36 if( aim_pos<=mid ) update( aim_pos,aim_value,l,mid,left( n ) ); 37 else update( aim_pos,aim_value,mid+1,r,right( n ) ); 38 anode[ n ].sum = max( anode[ left( n ) ].sum,anode[ right( n ) ].sum ); 39 } 40 41 int query( int a,int b,int l,int r,int n ){ 42 if( a==l&&b==r ){ 43 return anode[ n ].sum; 44 } 45 int mid = (l+r)/2; 46 if( b<=mid ) return query( a,b,l,mid,left( n ) ); 47 else if( mid<a ) return query( a,b,mid+1,r,right( n ) ); 48 else return max( query( a,mid,l,mid,left( n ) ),query( mid+1,b,mid+1,r,right( n ) ) ); 49 } 50 51 int main(){ 52 int n ,d; 53 while( scanf("%d%d",&n,&d)==2 ){ 54 memset( dp,0,sizeof( dp )); 55 int maxNum = 0; 56 for( int i=1;i<=n;i++ ){ 57 scanf("%d",&data[i]); 58 maxNum = max( maxNum,data[ i ] ); 59 } 60 build( 0,maxNum,1 ); 61 int ans = 1; 62 for( int i=1;i<=n;i++ ){ 63 if( i-d>1 ) 64 update( data[ i-1-d ],dp[ i-1-d ],0,maxNum,1 ); 65 if( data[ i ]>0 ) dp[ i ] = query( 0,data[ i ]-1,0,maxNum,1 )+1; 66 else dp[ i ] = 1; 67 ans = max( ans,dp[ i ]) ; 68 } 69 printf("%d ",ans); 70 } 71 return 0; 72 }