题目大意:给出数组的前三个数,a[1] = 1, a[2] = 2, a[3] = 3,再给出递推公式a[i] = (a[-1] + a[i-2] + a[i-3]) % m + 1, 

现在给出n,m,k分别表示数组有n个,m就是所要求余的数,k表示有k个数字

现在要求你在这个数组中找到一个长度最短的序列,里面要求包含(1,2,3。。。k)这k个数


解题思路:将所有大于k的数全部转换为0,这样就可以省去一些麻烦了。

用一个数组纪录1--k这k个数每个数出现的个数。

要求这k个数都存在,那么只需要用一个变量纪录出现了几个数字即可。因为要求最短的序列,所以还要进行删减,删减的时候要保证所需要的数的数目要大于1才可以进行删减


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1000010
#define maxm 1010
int num[maxn], cnt[maxm], n, m, k;

void init() {
	scanf("%d%d%d", &n, &m, &k);
	num[1] = 1, num[2] = 2, num[3] = 3;
	for(int i = 4; i <= n; i++)
		num[i] = (num[i - 1] + num[i - 2] + num[i - 3]) % m + 1;
	for(int i = 1; i <= n; i++) 
		if(num[i] > k)
			num[i] = 0;
	
}

void solve() {
	memset(cnt,0,sizeof(cnt));
	int Min = 0x3f3f3f3f, j = 1, count = 0;
	for(int i = 1; i <= n; i++) {
		if(num[i] && !cnt[num[i]]) 
			count++;
		cnt[num[i]]++;

		while(j < i && (!num[j] || cnt[num[j]] > 1))
			--cnt[num[j]], j++;
		if(count == k) {
			Min = min(Min,i - j + 1);
		}
	}
	if(Min == 0x3f3f3f3f)
		printf("sequence nai\n");
	else
		printf("%d\n", Min);
}

int main() {
	int test, mark = 1;
	scanf("%d", &test);
	while(test--) {
		init();
		printf("Case %d: ", mark++);
		solve();
	}
	return 0;
}