zafu 1467

终于把校赛最后一题过了,二分的地方写的很差,以后注意改进。思路就是从前向后求LIS最长递增子序列,以a[i]为底LIS值记录在dp1[i],

然后从后向前求LDS最长递减子序列,以a[i]为底LDS值记录在dp2[i]

则如果 dp1[i] + dp2[i]== dp[n]+1( 即最长长度加1 ),则说明a[i]是最长中的某个数,如果这些符合的dp1[i]值只出现一次,则其为

Key Number

题目链接 http://info.zjfc.edu.cn/acm/problemDetail.aspx?pid=1467

代码
#include<stdio.h>

#define maxn 100005
int dp1[maxn],dp2[maxn];
int a[maxn];
int hash[maxn];
int stack[maxn];
int n;
int kin;

void LIS( int k )
{
int i,j;
int end,front,mid;

int top=1;
stack[top]
=a[k];
dp1[
1]=1;

for( i=k+1 ; i<=n ; i++ )
{
if( a[i] > stack[ top ] )
{
stack[
++top ] = a[i] ;
dp1[i]
=top;//
}
else if( a[i]<=stack[1] )
{
stack[
1]=a[i];
dp1[i]
=1;
}
else
{
front
=1;
end
=top;
while( end>=front )
{
mid
=( front +end ) /2 ;
if( a[i]==stack[mid] )
{
dp1[i]
=mid;
break;
}
else if( a[i] > stack[mid] && a[i] <= stack[mid+1 ] )
{
stack[mid
+1]=a[i] ;
dp1[i]
=mid+1;//
break;
}
else if( a[i] <stack[mid] )
end
=mid-1;
else if(a[i]>stack[mid+1 ] )
front
=mid+1;

}

}

}
kin
=top;
}


void LDS( int k )
{
int i,j;
int end,front,mid;
int top=1;
stack[top]
=a[k];
dp2[k]
=1;
for( i=k-1 ; i>0 ; i-- )
{
if( a[i] < stack[ top ] )
{
stack[
++top ] = a[i] ;
dp2[i]
=top;
}
else if( a[i]>=stack[1] )
{
stack[
1]=a[i];
dp2[i]
=1;
}
else
{
front
=1;
end
=top;
while( end>=front )
{
mid
=( front +end ) /2 ;
if( a[i]==stack[mid] )
{
dp2[i]
=mid;
break;
}
else if( a[i] < stack[mid] && a[i] >= stack[mid+1 ] )
{
stack[mid
+1]=a[i] ;
dp2[i]
=mid+1;
break;
}
else if( a[i] > stack[mid] )
end
=mid-1;
else if(a[i] < stack[mid+1 ] )
front
=mid+1;

}

}

}

}

int main()
{
int t,i,j,k;
scanf(
"%d",&t);
while( t-- && scanf("%d",&n)!=EOF )
{
for( i=0; i<=n; i++)//初始
hash[ i ]=0;

for(i=1;i<=n;i++)
scanf(
"%d",&a[i] );

LIS(
1 ) ;
LDS( n ) ;

for( i=1;i<=n;i++ )
{
if( dp1[i]+dp2[i] == kin+1 )
hash[ dp1[i] ]
++ ;
}

int sum=0;
for(i=1;i<=n;i++)
if ( hash[i]==1 )
sum
++;

printf(
"%d\n",sum);
}

return 0;
}

 

 


 

 

posted on 2010-12-04 08:18  翱翔九天  阅读(307)  评论(0)    收藏  举报