zafu 1467 (DP)
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
样例输出
3
0
3
来源
浙江农林大学第十届电脑节程序设计大赛正式赛
/* 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; }