[洛谷P3948]数据结构

题目大意:有n个数,opt个操作,并给你md、min、max。

每种操作有以下两种:1.给一段区间加一个固定值。2.询问一段区间内满足$min\leq T*i\ mod\ md\leq max$(T是当前的数,i是当前数的下标)的数的个数。

在这opt个操作里,询问不超过1000个。

这之后还有final($<10^7$)个询问(同上面的询问),保证这些询问中间没有修改操作。

要你实现这些操作。

解题思路:一开始被这些巨大的数据唬住了,经过思考看了标程后突然发现并不是很难。

对于区间和操作,很容易想到差分解决,但中间还有询问操作,怎么办?

题目说中间最多1000个询问,而n最大才80000,对于每一个询问,都扫描一遍差分数组的话,不考虑常数则要执行大约80000000次操作。

标程告诉我这样是可以卡过去的(洛谷神评测机)。

再来考虑后面的询问,由于没有了修改操作,我们可以维护一个前缀和,来实现$O(1)$询问。

然后就玄学地卡了过去。

C++ Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#define ll long long
int n,opt,mod,min,max,l,r,b[80003];
ll a[80003];
char c;
inline int readint(){
	char c=getchar();
	bool b=false;
	for(;!isdigit(c);c=getchar())b=c=='-';
	int d=0;
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^'0');
	return b?-d:d;
}
inline void putint(int p){
	if(p==0){
		putchar('0');
		putchar('\n');
		return;
	}
	int w=1;
	while(w<=p)w*=10;w/=10;
	while(w){
		putchar(p/w+'0');
		p%=w;
		w/=10;
	}
	putchar('\n');
}
int main(){
	n=readint(),opt=readint(),mod=readint(),min=readint(),max=readint();
	memset(a,0,sizeof a);
	while(opt--){
		for(c=getchar();!isalpha(c);c=getchar());
		l=readint(),r=readint();
		if(c=='A'){
			int num=readint();
			a[l]+=num,a[r+1]-=num;
		}else{
			int cnt=0;
			ll sum=0;
			for(int i=1;i<=r;++i){
				sum+=a[i];
				if(i>=l)cnt+=(int)(sum%mod*i%mod>=min&&sum%mod*i%mod<=max);
			}
			putint(cnt);
		}
	}
	b[0]=0;
	ll sum=0;
	for(int i=1;i<=n;++i){
		sum+=a[i];
		b[i]=b[i-1]+(int)(sum%mod*i%mod>=min&&sum%mod*i%mod<=max);
	}
	for(int final=readint();final--;){
		l=readint(),r=readint();
		putint(b[r]-b[l-1]);
	}
	return 0;
}

 

转载于:https://www.cnblogs.com/Mrsrz/p/7772731.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值