题意:一次考试,学生成绩被分为k等,学校要抽取学号连续的若干学生,使得得到i等的学生数量在 [li,ri] 期间内。 n,k≤200000
单调队列,一个头指针,两个尾指针,一个尾指针记最小的符合下界的尾,另一个尾指针记最大的符合上界的尾。答案就是两个尾指针之间的部分。(细节挺多的)
const
MAXN=200050;
INF=maxlongint>>1;
var
a,l,r,cnt1,cnt2:array[0..MAXN] of longint;
n,k,i,p,q1,q2,legal:longint;
ans:int64;
function max(a,b:longint):longint;
begin if (a>b) then exit(a) else exit(b); end;
begin
assign(input,'survey.in');reset(input);
assign(output,'survey.out');rewrite(output);
read(n,k);
for i:=1 to n do read(a[i]);
for i:=1 to k do read(l[i],r[i]);
fillchar(cnt1,sizeof(cnt1),0);
fillchar(cnt2,sizeof(cnt2),0);
p:=1;q1:=0;q2:=0;legal:=0;cnt1[0]:=INF;cnt2[0]:=INF;
for i:=1 to k do
inc(legal,ord(cnt1[i]>=l[i]));
while (p<=n) do
begin
while (q2+1<=n)and(cnt2[a[q2+1]]+1<=r[a[q2+1]]) do
begin inc(q2);inc(cnt2[a[q2]]);end;
while (q1+1<=n+1)and(legal<k)and(cnt1[a[q1+1]]+1<=r[a[q1+1]]) do
begin inc(q1);inc(cnt1[a[q1]]);inc(legal,ord(cnt1[a[q1]]=l[a[q1]]));end;
if (q1>n) then break;
if (legal=k) then inc(ans,q2-q1+1);
if (p<=q1) then
begin
dec(legal,ord(cnt1[a[p]]=l[a[p]]));
dec(cnt1[a[p]]);dec(cnt2[a[p]]);
end;
inc(p);
q1:=max(q1,p-1);
q2:=max(q2,p-1);
end;
writeln(ans);
close(input);close(output);
end.