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
1 2 3
2 2 1
9 1093 1200 1321 1000 0 2 7 3 12

样例输出

3
0
3

作者

Zhuangli

来源

浙江农林大学第十届电脑节程序设计大赛正式赛

 

/*

	    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;

}

你可能感兴趣的:(dp)