子序列
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
5
-
描述
-
给定一个序列,请你求出该序列的一个连续的子序列,使原串中出现的所有元素皆在该子序列中出现过至少1次。
如2 8 8 8 1 1,所求子串就是2 8 8 8 1。
-
输入
-
第一行输入一个整数T(0<T<=5)表示测试数据的组数
每组测试数据的第一行是一个整数N(1<=N<=1000000),表示给定序列的长度。
随后的一行有N个正整数,表示给定的序列中的所有元素。
数据保证输入的整数都不会超出32位整数的范围。
输出
- 对于每组输入,输出包含该序列中所有元素的最短子序列的长度 样例输入
-
2 5 1 8 8 8 1 6 2 8 8 8 1 1
样例输出
-
2 5
解题思路:这道题数据比较大,可以先用离散化。接下来就是经典的尺取法了。。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> #include<map> using namespace std; const int maxn = 1000005; const int inf = 0x3f3f3f3f; int n,cnt,a[maxn],tmp[maxn]; int idx[maxn],Count[maxn]; int bisearch(int l,int r,int key) { int mid; while(l <= r) { mid = (l + r) >> 1; if(tmp[mid] == key) return mid; else if(tmp[mid] < key) l = mid + 1; else r = mid - 1; } } void Discrete() { sort(tmp+1,tmp+1+n); cnt = 0; tmp[++cnt] = tmp[1]; for(int i = 2; i <= n; i++) if(tmp[i] != tmp[i-1]) tmp[++cnt] = tmp[i]; for(int i = 1; i <= n; i++) idx[i] = bisearch(1,cnt,a[i]); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); tmp[i] = a[i]; } Discrete(); memset(Count,0,sizeof(Count)); int r = 1,sum = 0,ans = inf; for(int i = 1; i <= n; i++) { if(Count[idx[i]] == 0) sum++; Count[idx[i]]++; while(sum == cnt) { Count[idx[r]]--; if(Count[idx[r]] == 0) sum--; ans = min(ans,i - r + 1); r++; } } printf("%d\n",ans); } return 0; }
-
第一行输入一个整数T(0<T<=5)表示测试数据的组数