题意
Time Limit: 1000MS
Memory Limit: 65536KB
Description
将一个给定的数列,拆分成K个不降序列,每个数出现且只出现一次,且在各序列中各个数相对于原数列的相对顺序不变。
如7 6 9 8 10可以拆成 7 9 10和6 8。求最小的K值。
Input
第一行输入一个整数T(1 <= T <= 100),表示接下来T组测试数据,
每组两行,第一行为n,代表数列长度(1<=n<=10000)
接下来一行有n个数,空格分隔(每个数<=50000)。
Output
对每组数据输出一个最小的K值。
Sample Input
2
5
7 6 9 8 10
5
5 4 3 2 1
Sample Output
2
5
思路
维护一个数组,保存多个非递减序列的最后一个值。
显然,这个数组一定是递减的。
例如上面样例中的 7 6 9 8 10
初始时,我们令a[0] = 7,表示目前有一个序列,最后一个值为7
接下来到6了,因为6小于7,所以只能使用一个新的序列,令a[1] = 6
到9,我们发现9既可以放在7后面,也可以放在6后面,那我们当然选择在7后面放,相比放在6后面会更好。
也就是说,假如当前需要放入x,那就在数组中找小于等于x的最大值,更新它为x。
因为数组是递减的,所以寻找的这个过程可以使用二分查找。
代码
#include<iostream>
#include<algorithm>
#include<list>
#include<vector>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stack>
#include<queue>
using namespace std;
#define LL long long
int d[50009];
int find(int l, int r, int x)
{
while(l <= r)
{
int mid = (l+r)/2;
if(x < d[mid])
l = mid+1;
else if(x > d[mid])
r = mid-1;
else
return mid;
}
return l;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
int len = 0;
d[len] = 0;
for(int i=0; i<n; i++)
{
int t;
scanf("%d", &t);
int z = find(0, len, t);
if(z > len)
d[++len] = t;
else
d[z] = t;
}
printf("%d\n", len+1);
}
return 0;
}