luogu题解 UVA11536 Smallest Sub-Array最短set区间&滑动窗口
Posted Rye_Catcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu题解 UVA11536 Smallest Sub-Array最短set区间&滑动窗口相关的知识,希望对你有一定的参考价值。
- 题目链接:
https://www.luogu.org/problemnew/show/UVA11536
- 题目大意:
给定一个\(N,M,K\),构造这样的数列:
\(x[1]=1,x[2]=2,x[3]=3\)
\(x[i]=(x[i-1]+x[i-2]+x[i-3])\mod M+1(N>=i>=4)\)
然后问你是否存在一个在\(x[1]\)到\(x[n]\)中的区间,使得\([1,K]\)所有元素在其中至少出现过一次。
若存在,输出这个区间最短长度;否则输出\("sequence\) \(nai"\)
有T组数据
- 分析:
我们可以想到用滑动窗口的改进做法。
搞一个左指针\(l\),右指针\(r\),和一个\(cnt\)数组记录每个元素相对应在\([l,r]\)中的出现次数。
然后不断尝试右移\(r\),同时将\(cnt[x[r]]++\),如果\(cnt[x[r]]==1\),就让\(done++\),表示多了一个新元素出现在区间内,如果\(done==k\),说明所有元素出现过一次,这时尝试右移左指针,用上面类似的操作,只不过判定有所区别,直到\(done!=k\)说明不满足性质,记录下此时\(r-l\)长度,再重复右移\(r\)的操作
其实如果你对莫队有了解的话这些应该很容易理解
- 注意:
庆幸的是由于\(\mod M\)的限制,数列中的数都很小,可以直接记录,不必用map或离散化
- 代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#define inf 0xfffffff
using namespace std;
const int maxn=1000009;
int t,n,m,k;
int f[maxn];
int cnt[1005];
int main(){
scanf("%d",&t);
for(register int ite=1;ite<=t;ite++){
memset(cnt,0,sizeof(cnt));
scanf("%d %d %d",&n,&m,&k);
f[1]=1,f[2]=2,f[3]=3;
for(register int i=4;i<=n;i++)f[i]=(f[i-1]+f[i-2]+f[i-3])%m+1;
int l=1,r=1,done=0,ans=inf;
while(r<n){
int g=f[r++];
if(g>=1&&g<=k)cnt[g]++;
if(cnt[g]==1)done++;
while(done==k&&l<r){
ans=min(ans,r-l);
g=f[l++];
cnt[g]--;
if(cnt[g]==0)done--;
}
}
printf("Case %d: ",ite);
if(ans==inf)puts("sequence nai");
else printf("%d\n",ans);
}
return 0;
}
以上是关于luogu题解 UVA11536 Smallest Sub-Array最短set区间&滑动窗口的主要内容,如果未能解决你的问题,请参考以下文章
Uva - 11536 - Smallest Sub-Array