有n (n≤106) 个0 ~ m - 1 (m≤1000) 的整数组成一个序列。输入k (k≤100) ,你的任务是找一个尽量短的连续的子序列 (xa,xa+1,xa+2,...,xb−1,xb) ,使得该子序列包含1 ~ k的所有整数。例如,n = 20, m = 12, k = 4,序列为1 ( 2 3 7 1 12 9 6 3 7 5 4 ) 5 3 1 10 3 3,括号内部分是最优解。如果不存在满足条件的连续子序列,输出sequence nai。(本段摘自《算法竞赛入门经典(第2版)》)
分析:
滑动窗口思想,直接扫描一遍即可,复杂度为
O(n)
。
代码:
#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
using namespace std;
const int maxn = 1000000 + 5, INF = 1000000 + 5;
int T, n, m, k, num, ans, tmp;
int a[maxn], x[105];
int main()
{
scanf("%d", &T);
for (int C = 0; C < T; ++C)
{
scanf("%d%d%d", &n, &m, &k);
a[0] = 1;
a[1] = 2;
a[2] = 3;
for (int i = 3; i < n; ++i)
a[i] = ((a[i - 3] + a[i - 2] + a[i - 1]) % m) + 1;
ans = INF;
num = 0;
memset(x, 0, sizeof(x));
queue< int > q;
for (int i = 0; i < n; ++i)
{
if (a[i] <= k)
{
q.push(i);
++x[a[i]];
if (x[a[i]] == 1)
++num;
}
while (num == k)
{
tmp = i - q.front() + 1;
ans = min(ans, tmp);
if (--x[a[q.front()]] == 0)
--num;
q.pop();
}
}
printf("Case %d: ", C + 1);
if (ans != INF)
printf("%d\n", ans);
else
printf("sequence nai\n");
}
return 0;
}