P3948数据结构

题目描述

给出 n n n o p t opt opt m o d mod mod m i n min min m a x max max m o d mod modint 范围内

操作 A A A Q Q Q

A A A: L L L, R R R, X X X 表示把 [ l , R ] [l,R] [l,R]这个区间加上 X X X

Q Q Q: L L L, R R R 表示询问 [ L , R ] [L,R] [L,R]这个区间中元素T满足 m i n < = ( T × i % m o d ) < = m a x min<=(T\times i \% mod)<=max min<=(T×i%mod)<=max 的 T这样的数的个数(i是数组下标)

你的询问操作不会超过 1000 1000 1000 次,不幸的是,对于延后的询问操作可能有很多次(小于 1 0 7 10^7 107 次),但是保证这些延后的询问操作之后不会再次有修改操作(就是在最后会有很多次询问,但不会进⾏修改)。

分析

J 组算法轻松解决。

观察到 o p t opt opt 虽然有 1 0 6 10^6 106 次,但是询问操作最多只有 1000 1000 1000 次,很容易想到差分,而每次询问时直接给差分数组求前缀和统计答案即可。

而其延后操作虽然有很多次,但是没有修改,所以可以用前缀和维护前 i i i 项的合法方案数即可。

代码

代码实现有些技巧。

#include 
#define int long long
/*要开long long不然会溢出*/
using namespace std;

const int N = 1e5 + 5;
int n, opt, mod, minn, maxn, final, a[N], pre[N], diff[N];

signed main(){
	ios::sync_with_stdio(false);//关闭同步流
	cin.tie(NULL); cout.tie(NULL);//调试用的
	cin >> n >> opt >> mod >> minn >> maxn;
	while(opt --){
		char c;
		int l, r, x;
		cin >> c >> l >> r;
		if(c == 'A'){
			cin >> x;
			diff[l] += x;//差分都会吧
			diff[r + 1] -= x;	
		}else{
			int cnt = 0;
			for(int i = 1; i <= n; i ++){
				a[i] = a[i - 1] + diff[i];
				int tmp = (a[i] * i) % mod;//这里不要写错
				if(tmp >= minn && tmp <= maxn && i >= l && i <= r){//统计合法方案数
					cnt ++;
				}
			}
			cout << cnt << "\n";
		}
	}
	for(int i = 1; i <= n; i ++){//前缀和维护合法方案数
		pre[i] = pre[i - 1];
		diff[i] += diff[i - 1];//对差分数组求前缀和
		int tmp = (diff[i] * i) % mod;
		if(tmp >= minn && tmp <= maxn){//合法则方案数加1
			pre[i] ++;
		}
	}
	cin >> final;
	while(final --){
		int l, r;
		cin >> l >> r;
		cout << pre[r] - pre[l - 1] << "\n";//容斥原理,输出答案
	}
	return 0;
}

你可能感兴趣的:(数据结构,c++,算法)