日常训练20161014 成绩调研

本文介绍了一种用于统计连续学号区间内各成绩等级人数的算法。通过维护两个指向不同条件限制下的队列尾部的指针,实现高效查找满足条件的学号区间。适用于大规模数据处理。

题意:一次考试,学生成绩被分为k等,学校要抽取学号连续的若干学生,使得得到i等的学生数量在 [li,ri] 期间内。 n,k200000

单调队列,一个头指针,两个尾指针,一个尾指针记最小的符合下界的尾,另一个尾指针记最大的符合上界的尾。答案就是两个尾指针之间的部分。(细节挺多的)

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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值