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;
}

原文地址:https://www.cnblogs.com/Rye-Catcher/p/9094648.html

时间: 2024-08-30 10:23:11

luogu题解 UVA11536 【Smallest Sub-Array】最短set区间&滑动窗口的相关文章

leetcode 题解:Merge Sorted Array(两个已排序数组归并)

题目: Given two sorted integer arrays A and B, merge B into A as one sorted array. Note:You may assume that A has enough space (size that is greater or equal to m + n) to hold additional elements from B. The number of elements initialized in A and B ar

【LuoGu题解】 P1362 【兔子数】

依题意模拟暴力打表找规律,注意到:符合题意的数中只包含\(0,1,2,3\),大于\(3\)的数,平方后都会进位,进位导致\(S(x)*S(x)<S(x*x)\) 观察数据范围,最大满足题意的数字有\(10\)位,那么我们枚举每一位上的数字,然后暴力判断是否为兔子数就行了. Code: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #inclu

luogu 1886 滑动窗口

题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array is [1 3 -1 -3 5 3 6 7], and k = 3. 输入格式 输入一共有两行,第一行为n,k. 第二行为n个数(<INT_MAX). 输出格式 输出共两行,第一行为每次窗口滑动的最小值 第二行为每次窗口滑动的最大值 输入输出样例 输入 #1复制 8 3 1 3 -1 -3 5 3 6 7

luogu P1886滑动窗口

\(luogu\ P1886\)滑动窗口 题目链接 这道题目比较简单,但是因为经常忘记单调队列做滑动窗口所以写博客来加深一下印象. 如果求区间最小值,我们用发现右端点从前往后扫的方法一个数如果有贡献,当且仅当当前扫描的右端点的前面到这个数中间没有比这个数更小的数,因为如果有比这个数更小的数的话,这个更小的数肯定就会成为区间的最小值.如果一个数没有贡献的时候就是区间的左端点比这个数的下标要大的时候. 所以我们用一个双端队列来维护,每次进入队列的时候检查队尾的数如果比要加入得数大的话,就不断弹出队尾

【luogu题解】P1546 最短网络 Agri-Net

题目 约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场.为了用最小的消费,他想铺设最短的光纤去连接所有的农场. 你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案.每两个农场间的距离不会超过100000. 输入 第一行: 农场的个数,N(3<=N<=100). 第二行..结尾: 后来的行包含了一个N*N的矩阵,表示每个农场之间的距离.理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,他们限制在80个字符,因此,某些行会紧接着另一些

luogu题解 P2184 【贪婪大陆】

题目链接: https://www.luogu.org/problemnew/show/P2184 思路: 首先我想吐槽一下为什么现有题解中的做法都是一样的,而且还比较难以理解; 我就讲下我的做法,本质上是一样的,但是跟容易理解. 根据题意每加一次地雷就多一个种类对吧,我们用一个cnt记录加过地雷的次数,同时分别用两个数组记录左右两个端点的位置.然后查询[l,r]时呢,我们分别查询[1,l-1]有多少个右端点,[r+1,n]有多少个左端点,然后这两个数的和是什么意思呢?就是有多少次铺地雷没铺到我

luogu题解P2486[SDOI2011]染色--树链剖分+trick

题目链接 https://www.luogu.org/problemnew/show/P2486 分析 看上去又是一道强行把序列上问题搬运到树上的裸题,然而分析之后发现并不然... 首先我们考虑如何在序列上维护信息:从最简单的想起,如果两个相邻的元素合并,显然是这两个元素所含颜色段个数(其实就是1)加起来,如果两个元素颜色相同就减1;那么两个分别含有两个元素的相邻区间合并,还是把这两个区间所含颜色段个数加起来,如果左区间最右边的颜色等于右区间最左边的颜色就减去1. 如此我们已经得到线段树维护信息

luogu题解P1032字串变换--BFS+STL:string骚操作

题目链接 https://www.luogu.org/problemnew/show/P1032 分析 这题本来很裸的一个BFS,发现其中的字符串操作好烦啊.然后就翻大佬题解发现用STL中的string居然变得这么简洁!!! 各种string操作请看另一位大佬博客,写得很全啊: https://www.cnblogs.com/rvalue/p/7327293.html#commentform 其实我们这题只用到两个相关函数:\(S.find(string,pos)\)和\(S.substr()\

uva11536 Smallest Sub-Array

Thinking about it: 我的思路跟sliding window有点类似.假设已经确定了一个区间[l, r],序列中从 l 到 r 恰好包含了[1, K]的各个元素,则从 r 开始继续迭代序列的各个位置,如果发现了1到K的数,则做以下处理: 如果 这个数 刚好是 l 位置上的数,那么就意味着这个区间可能缩短,则同时更新 l 和 r,计算区间长度的变化. 如果 这个数 不是 l 上的数,那么即使 更新了 r 那也不能使答案更好,所以可以不做处理. 那么第一个符合条件的[l, r]可以直