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;
}

浙公网安备 33010602011771号