您的位置:首页 > 其它

[NOIP2017模拟]count

2017-09-16 22:48 295 查看
题目背景

SOURCE:NOIP2015-SHY-8

题目描述

给定一个元素个数为 n 的整数数组 a 和 Q 个问题,每个问题有 x,y 两个参数,请统计共有多少个整数 K 满足 K 在 a[x]…a[y] 中出现了恰好 K 次。

输入格式

第一行两个整数 n,Q,表示数组 a 的元素个数和询问数;

接下来一行 n 给整数,描述数组 a ;

接下来 Q 行,每行两个数 xi,yi(1≤xi≤yi≤n),表示询问的左右边界。

输出格式

输出 Q 行,每行一个整数表示满足询问的 K 的个数。

样例数据

输入

7 2

3 1 2 2 3 3 7

1 7

3 4

输出

3

1

备注

【样例说明】

Q1: 1、2、3 分别满足,所以共有 3 个数满足要求。

Q2: 2 满足,所以只有 1 个数满足要求。

【数据范围】

对 50% 的输入数据:1≤n,Q≤1000

对 100% 的输入数据:1≤n,Q≤100000,1≤a[i]≤109

分析:这道题用莫队算法,什么是莫队算法呢,就是用前一个询问更新后一个,而这道题要分块,好处是把排序O(n2)降到了O(n√n)。将询问排序,一个询问计算出来之后与下一个询问左右边界比较,然后移动左右边界更新答案。

注意:若前一个询问l(或r)在后一个之外,那么就要从l开始更新;而如果在后一个之内,就要从l之前一个(r之后一个)更新。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;ch>='0'&&ch<='9';ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}

const int maxn=100010;
struct node{
int l,r,id,pos;
}q[maxn];
int n,Q,s,res;
int a[maxn],c[maxn],ans[maxn];

bool comp(const node &a,const node &b)
{
if(a.id==b.id)
return a.r<b.r;
return a.id<b.id;
}

int main()
{
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);

n=getint();Q=getint();
for(int i=1;i<=n;++i)
{
a[i]=getint();
if(a[i]<=n) c[a[i]]++;
}

for(int i=1;i<=n;++i)
if(c[i]==i) res++;

s=(int)sqrt(n);
for(int i=1;i<=Q;++i)
{
q[i].l=getint(),q[i].r=getint();
q[i].id=q[i].l/s+1;
q[i].pos=i;
}

sort(q+1,q+Q+1,comp);

int l=1,r=n;
for(int i=1;i<=Q;++i)
{
while(l<q[i].l)
{
if(a[l]>n)
{
l++;
continue;
}
if(a[l]==c[a[l]]) res--;
if(a[l]==c[a[l]]-1) res++;
c[a[l]]--;
l++;
}

while(l>q[i].l)//边界
{
l--;
if(a[l]>n)
continue;
if(a[l]==c[a[l]]) res--;
if(a[l]==c[a[l]]+1) res++;
c[a[l]]++;
}

while(r>q[i].r)
{
if(a[r]>n)
{
r--;
continue;
}
if(a[r]==c[a[r]]) res--;
if(a[r]==c[a[r]]-1) res++;
c[a[r]]--;
r--;
}

while(r<q[i].r)//边界
{
r++;
if(a[r]>n)
continue;
if(a[r]==c[a[r]]) res--;
if(a[r]==c[a[r]]+1) res++;
c[a[r]]++;
}

ans[q[i].pos]=res;
l=q[i].l,r=q[i].r;
}

for(int i=1;i<=Q;++i)
cout<<ans[i]<<'\n';
return 0;
}


本题结。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: