P8249 模法问题

发布时间 2024-01-07 16:28:29作者: cloud_eve

题目传送门

思路

正在做数学且这痴迷于判断的我看见这道题的题目:法游戏,肥肠激动,决定用我聪明的大脑考虑所有情况并用 if 求解。

and then:to be continued~~~

code

当乐子看就行了。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll mod1, mod2, l, r, ans;
void check(int mod) {
	int t = r / mod;
	if ((l - r) >= mod) ans += mod - 1;
	else if (l < (t * mod)) ans += mod - 1;
	else ans += max(l % mod, r % mod);
}
int main() {
	int T;
	scanf("%lld%lld%d", &mod1, &mod2, &T);
	while (T--) {
		scanf("%lld%lld", &l, &r);
		ans = 0;
		check(mod1), check(mod2);
		printf("%lld\n", ans);
	}
	return 0;
}

惨痛的失败。我发现简单的判断解决不了这道题,决定思考一下看题解

明显的,数据沒有水到用 if 就可以直接过的地步,所以考虑多进行几次判断。现在我们需要在循环判断最大值之前,考虑直接存在的最大值。
学过小学奥数都知道,对于两个模数 \(a\)\(b\),每连续的 \(a \times b\) 个数中一定有可以同时整除这两个数的数。

证明:很简单,直接枚举就可以

基于上面的结论,也可以得出每连续 \(a \times b\) 个数中一定有 \(i\) 可以满足 \(i \bmod a = a - 1\)\(i \bmod b = b - 1\)。此时直接输出 \(a + b - 2\) 即可。

对于不满足上面情况的,考虑循环。

试问 \(i\) 在什么时候是有意义的呢?答案是 \(i \bmod a > (i - 1) \bmod a\) 时。同理,当 \(i \bmod b > (i - 1) \bmod b\) 时,这个答案是有意义的。那么综合上述的结论,我们就可以设 ans = r % a + r % b

如何设置循环中 \(i\) 的初值呢?已知对于模数 \(a\),对其取模的结果中最大的应为 \(t \times a - 1(t \ge 1)\)。在循环中,我们希望 \(i\) 尽可能满足对 \(a\) 取模时最大,所以可以设 i = t * a + a - 1。又因为 \(i\) 应从 \(l\) 开始,所以对于 \(t\),将其定义为 t = l / a,就可以得到一个大于 \(l\) 且与 \(l\) 最接近且对 \(a\) 取模答案最大的 \(i\)

在取模的运算中,i % a(i + a) % a 是等价的,所以可以将末尾循环体的修改记为 i += a,提升效率。

根据题意,答案需要满足同时对 \(a\)\(b\) 取模最大,又已知 \(i\) 已经是对 \(a\) 取模中最大的数,所以在循环中只需要考虑对 \(b\) 取模是否最大即可。

第二个循环想法同理。

关于为什么有第二个循环:
我们不知道 \(p \in [l, r]\) 中是否有数满足 \(p = n \times a - 1\)\(p = m \times b - 1\),所以分别将以上两种 \(p\) 作为循环中的 \(i\),做两次求值。

具体实现见代码。

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a, b, l, r, ans;
void get_ans(ll x, ll y) {
	int t = l / x;
	for (int i = (t + 1) * x - 1; i <= r; i += x)
		ans = max(ans, x - 1 + i % y);
}
int main() {
	int T;
	scanf("%lld%lld%d", &a, &b, &T);
	while (T--) {
		scanf("%lld%lld", &l, &r);
		if (l / (a * b) != r / (a * b)) ans = a + b - 2; //l 和 r 之间有大于 a*b 个连续的数
		else {
			ans = r % a + r % b;
			get_ans(a, b), get_ans(b, a);
		}
		printf("%lld\n", ans);
	}
	return 0;
}

long long 是没有必要的;
理论最差的时间复杂度为 \(O(q(a + b))\),约 \(O(2 \times 10^8)\)
暂时是最优解。

谢谢管理员 @yummy 的多次审核和指导,求通过!