Key Number
时间限制 : 1000 ms 内存限制 : 32 MB
提交次数 : 70 通过次数 : 34
题目描述
我们称在一个序列中,按顺序出现的递增元素(不必连续)所构造出的最长序列集合为该序列的最长递增子序列。
例如序列1 3 2 8 4 9,它含有一些递增子序列,如:1 3;1 2 8;1 2 4 9;1 3 8 9等。
其中,我们无法找到长度大于4的递增子序列,所以该序列的最长递增子序列长度为4。 对于一个整数序列,
我们称其中的元素为不可分割之元素,当且仅当我们将它移去后,该序列的最长递增子序列的长度将会减小。
在上一段的例子中,9就是一个不可分割元素,因为去掉了9之后的序列为1 3 2 8 4,其最长递增子序列长度为3。
于是现在的问题是,给出一组整数序列,求当前序列中不可分割元素的数目。
输入描述
第一行是一个整数T(T<=100),表示测试组数。 对于每组数据,第一个整数n(n<=100000),表示序列的长度。 然后是n个不超过10000的整数。
样例输入
3
3
1 2 3
2 2 1
9 1093 1200 1321 1000 0 2 7 3 12
/*
lost神题;
dp[i]记录到i 出现的最长子序列的长度;
当 dp1[i]+dp2[n-i+1]==l+1
说明当前i包括在最长子序列内
;
注意 : dp1[i]指到当前i位置时出现的最长子序列,如果dp1[i]出现多次的话,说明当前的dp1[i]是可以替代的,
所以, hash[dp1[i]]++ , 线扫hash出现过一次的说明是不可删的,
*/
#include <stdio.h>
#include <math.h>
#include <string.h>
int queue[100001];
int dp1[100001],dp2[100001];
int s1[100001],s2[100001];
int hash[100001];
int n;
int LIS(int dp[],int s[])
{//求单调递增子序列
int lenth=1,left,right,mid;
queue[1]=s[1];dp[1]=1;
for(int i=2;i<=n;i++)
{
left=1;right=lenth;
while(left<right)
{
mid=(left+right)>>1;
if(queue[mid]<s[i])
left=mid+1;
else
right=mid;
}
if(queue[left]<s[i])
{
lenth++;right=lenth;
queue[lenth]=s[i];
dp[i]=left+1;
}
else
{
dp[i]=left;
queue[left]=s[i];
}
}
return lenth;
}
//
int LDS(int dp[],int s[])
{//单调递减子序列
int lenth=1,left,right,mid;
queue[1]=s[1];dp[1]=1;
for(int i=2;i<=n;i++)
{
left=1;right=lenth;
while(left<right)
{
mid=(left+right) >>1;//!!!!
if(queue[mid]>s[i])
left=mid+1;
else
right=mid;
}
if(queue[left]>s[i])
{
lenth++;right=lenth;
queue[lenth]=s[i];
dp[i]=left+1;
}
else
{
dp[i]=left;
queue[left]=s[i];
}
}
return lenth;
}
int main()
{
int lenth,left,num,right,i,j,l,T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&s1[i]);
s2[n+1-i]=s1[i];
}
l=LIS(dp1,s1);
LDS(dp2,s2);
memset(hash,0,sizeof(hash));
num=0;
for(i=1;i<=n;i++)
{
if(dp1[i]+dp2[n-i+1]==l+1)
hash[dp1[i]]++;
}
for(i=1;i<=n;i++) if(hash[i]==1) num++;
printf("%d\n",num);
}
return 0;
}