描述 Description | |||
给你一个长度为n的数字串,数字串里会包含1-m这些数字。如果连续的一段数字子串包含了1-m这些数字,则称这个数字字串为NUM串。你的任务是求出长度最短的NUM串是什么,只需要输出这个长度即可。 1<=n,m<=200000 | |||
输入格式 Input Format | |||
第一行给定n和m。 第二行n个数,表示数字串,数字间用空格隔开。 | |||
输出格式 Output Format | |||
如果存在NUM串则输出最短NUM串长度,否则输出“NO”。 | |||
样例输入 Sample Input [复制数据] | |||
|
|
| |
| 样例输出 Sample Output [复制数据] |
| |
|
这道题目开始以为特别难。。。还想了个二分优化。。。结果就10分。。
然后看了题解。。懂了。
脑补一个队列,i为首端,j为尾端。hash[k]表示队列里k的个数。
显然如果一个队列里满足对于hash[k],k属于[1..m] 都有hash[k]>=1
那么则次队列满足题目要求,len=i-j+1。
所以起始时刻i=1,j=1。用key来表示队列里面1..m元素的个数。若key=m则说明满足要求。
对于每一个入队的a[j]
如果hash[a[j]]=0 那么inc(key);
检查队头元素,每当hash[a[i]]>1时,要inc(i),因为此时不需要队头提供的a[i]。
当key=m时 用len 更新 min
var n,m,i,j,len,key,min:longint;
a:array[1..200000]of longint;
flag:boolean;
hash:array[1..200000]of longint;
begin
readln(n,m);flag:=false;
fillchar(hash,sizeof(hash),0);
min:=maxlongint;
for i:=1 to n do read(a[i]);
i:=1;j:=1;hash[a[1]]:=1;key:=1;
while j<=n do
begin
inc(j);
inc(hash[a[j]]);
if hash[a[j]]=1 then inc(key);
while hash[a[i]]>1 do
begin
dec(hash[a[i]]);
inc(i);
end;
if (key=m)and(j-i+1<min) then begin
flag:=true; min:=j-i+1; end;
end;
if not flag then writeln('NO')
else writeln(min);
readln;readln;
end.