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区间&滑动窗口的主要内容,如果未能解决你的问题,请参考以下文章

uva11536 Smallest Sub-Array

Uva - 11536 - Smallest Sub-Array

UVA - 11536 Smallest Sub-Array(尺取法)

luogu题解 UVA1615 Highway

luogu题解 UVA534 Frogger--最小瓶颈边

题解Luogu UVA1411 Ants