题目大意:给出数组的前三个数,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;
}