调查( 单调队列(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;
}