【Codeforces1342C】Yet Another Counting Problem(数论)

题目大意:

求有多少\(x(1\le l\le x\le r\le 10^{18})\)满足\((x\mod a)\mod b\neq(x\mod b)\mod a(1\le a,b\le 200)\),有\(q(1\le q\le 500)\)次询问。


设答案为\(f(l,r)\),考虑前缀和\(f(l,r)=f(1,r)-f(1,l-1)\),现在问题在于计算\(f(1,x)(1\le x\le 10^{18})\)

我们可以发现规律:对于任意的\(x\)\(y\)\(n\),有\(f(x,y)=f(x+nab,y+nab)\)

所以\(f(1,ab)=f(ab+1,2ab)=f(2ab+1,3ab)=......=f((n-1)ab+1,nab)\)

将上式变形,得到\(f(1,2ab)=2f(1,ab),f(1,3ab)=3f(1,ab),......,f(1,nab)=nf(1,ab)\)

\(x\mod ab=k\),则\(x=\lfloor\frac{x}{ab}\rfloor ab+k\)

所以\(f(1,x)=f(1,\lfloor\frac{x}{ab}\rfloor ab+k)=f(1,\lfloor\frac{x}{ab}\rfloor ab)+f(\lfloor\frac{x}{ab}\rfloor ab+1,\lfloor\frac{x}{ab}\rfloor ab+k)\)

\(=\lfloor \frac{x}{ab}\rfloor f(1,ab)+f(1,k)\)

由于\(ab\)\(k\)都是较小的数,我们可以在最开始时预处理出所有\(f(1,x)(1\le x\le ab)\)的结果。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,q;
ll ret[210*210];
ll f(ll x){
	return x/(a*b)*ret[a*b]+ret[x%(a*b)];
}
int main(){
	int T;
	cin >> T;
	while(T--){
		cin >> a >> b >> q;
		for(ll i=1;i<=a*b;i++){
			ret[i]=ret[i-1];
			if(i%a%b!=i%b%a){
				ret[i]++;
			}
		}
		while(q--){
			ll l,r;
			cin >> l >> r;
			cout << f(r)-f(l-1) << ' ';
		}
		cout << endl;
	}
	return 0;
}
posted @ 2023-08-28 16:55  Alric  阅读(15)  评论(0编辑  收藏  举报