调查

调查( 单调队列(star ))

  • 时限:(1s) 内存:(256M)

Descrption

  • (Ezio) 现在有一份调查列表,上面有 (n) 个人,每个人有一个编号,编号在 (1)(m) 之间,编号记录的是这个人与哪一条情报有关,(Ezio) 现在要调查 (1)(m) 所有的情报,每条情报只需要调查与该条情报有关的一个人即可,由于时间关系,(Ezio) 想要调查连续的一段人,并且调查的人数尽量少。

Input

  • 共两行,第一行两个数 (n,m)
  • 第二行 (n) 个数 第 (i) 个数是,第 (i) 个人的编号。每两个数中间有一个空格隔开,结尾无空格。

Output

  • 一个数,满足条件的最少人数。对于无解的情况,输出 (0)

Sample Input

7 6
6 1 2 4 4 5 3

Sample Output

7

Hint

  • (n<=5000000, m<=n)
  • 来源:(cogs2410)

分析

  • 典型的单调队列,和 (luoguP1638) 类似,用一个队列来维护,扫描整个序列,并记录元素出现的个数和新元素的个数,当队首元素的个数大于 (1) 时,说明后面有替代队首的相同元素,所以可以出队,当新元素个数等于 (m) 时,说明队列里 (1sim m) 都有了,维护一个最小值即可。

Code

#include <bits/stdc++.h>
typedef long long LL;
const int maxn= 5e6+5,Inf=0x3f3f3f3f;
int cnt[maxn],q[maxn],tail=0,head=1,tot,ans=Inf;
void Solve(){
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        int x;scanf("%d",&x);
        q[++tail]=x;
        if(!cnt[x])tot++;//x没有出现过
        cnt[x]++;//记录x出现的次数
        while(cnt[q[head]]>1)//队首元素个数不止一个
            cnt[q[head]]--,head++;
        if(tot==m)ans=std::min(ans,tail-head+1);
    }
    if(ans==Inf)
        printf("0
");
    else
        printf("%d
",ans);
}
int main(){
    Solve();
    return 0;
}
原文地址:https://www.cnblogs.com/hbhszxyb/p/13376565.html