UVa #12174 Shuffle (例题8-15)

来源:互联网 发布:诺基亚3500c软件 编辑:程序博客网 时间:2024/06/14 05:38

连续子序列。。又是滑动窗口哈


这道题用滑动窗口做的话,无非就是枚举第一个窗口的起始位置,从 -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;}

0 0