连续子序列。。又是滑动窗口哈
这道题用滑动窗口做的话,无非就是枚举第一个窗口的起始位置,从 -s+1 到 0。(用负数表示开头的不完整周期) 然后判断每个窗口是不是都符合没有重复数字的要求
这道题和之前的滑动窗口不太一样,这道题要简单些:窗口的大小是固定的。我们只需要把每个元素的前一个出现位置记下来,在滑动窗口进行判断的时候,挨个看每个元素的上一次/下一次出现位置有没有在窗口范围内就可以了
可是其实解一共只有s种可能,滑动窗口做的只不过是在不断的排除可能性。如果不是为了练习滑动窗口,我们可以用一个更简单的方法:对于每个位置上的元素 a,找到它下次出现的位置 b,如果它俩距离小于 s ,则将右端贴着 b 的滑窗一直到左端贴着 a 的滑窗全部排除,因为这些滑窗都会造成元素的重复出现。
这样只需要从左到右扫描一次即可,复杂度O(n)
Run Time: 0.768s
#define UVa "LT8-15.12174.cpp"
char fileIn[30] = UVa, fileOut[30] = UVa;
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
//Global Variables. Reset upon Each Case!
const int maxn = 100000 + 10;
int s, n, x[maxn], vis[maxn];
int dist_to_next[maxn];
/
int main() {
int T;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase ++) {
scanf("%d%d", &s, &n);
for(int i = 0; i < n; i ++) scanf("%d", &x[i]);
int last[maxn];
memset(dist_to_next, -1, sizeof(dist_to_next));
memset(last, -1, sizeof(last));
for(int i = 0; i < n; i ++) {
int u = x[i];
if(last[u] != -1) {
dist_to_next[last[u]] = i - last[u];
}
last[u] = i;
}
int vis[maxn];
int ans = s;
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i ++) {
if(dist_to_next[i] != -1) {
for(int j = (i + dist_to_next[i]) - s + 1; j <= i; j ++) {
int l = j % s;
if(j < 0) l = (j+s)%s;
if(vis[l] == 0) {
vis[l] = 1;
ans --;
}
}
}
}
printf("%d\n", ans);
}
return 0;
}