bzoj2506: calc

考虑离线,首先可以把每个询问的区间转化成[1,x]的形式

然后对询问的右端点排序

接着从左往右扫,记录每个数出现的次数,以及模数小于100的所有结果出现的次数

对于P小于100的询问,直接得到答案

对于P大于100的询问,暴力枚举得到答案

复杂度O(nsqrt(n))

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define N 233333

using namespace std;
inline int read(){
	int ret=0;char ch=getchar();
	while (ch<'0'||ch>'9') ch=getchar();
	while ('0'<=ch&&ch<='9'){
		ret=ret*10-48+ch;
		ch=getchar();
	}
	return ret;
}

int a[N],n;

struct query{
	int pos,P,mod,id;
	query(){}
	query(int _pos,int _P,int _mod,int _id):pos(_pos),P(_P),mod(_mod),id(_id){}
} q[N];
bool operator <(const query &x,const query &y){
	return x.pos<y.pos;
}

int ans[N],cnt[23333],res[233][333];

int main(){
	n=read();int Q=read(),m=0;
	for (int i=1;i<=n;++i) a[i]=read();
	for (int i=1;i<=Q;++i){
		int x=read(),y=read(),z=read(),tmp=read();
		q[++m]=query(x-1,z,tmp,-i);
		q[++m]=query(y,z,tmp,i);
	}
	sort(q+1,q+m+1);
	int j=1;
	memset(cnt,0,sizeof(cnt));
	memset(res,0,sizeof(res));
	memset(ans,0,sizeof(ans));
	for (int i=1;i<=m;++i){
		for (;j<=q[i].pos;++j){
			++cnt[a[j]];
			for (int k=1;k<=100;++k) ++res[k][a[j]%k];
		}
		int now=0;
		if (q[i].P>100)
			for (int k=0;k*q[i].P+q[i].mod<=10000;++k)
				now+=cnt[k*q[i].P+q[i].mod];
		else now=res[q[i].P][q[i].mod];
		ans[abs(q[i].id)]+=q[i].id/abs(q[i].id)*now;
	}
	for (int i=1;i<=Q;++i) printf("%d\n",ans[i]);
	return 0;
}

  

posted @ 2016-02-03 14:52  wangyurzee  阅读(187)  评论(0编辑  收藏  举报