P8249 模法问题
思路
正在做数学且这痴迷于判断的我看见这道题的题目:模法游戏,肥肠激动,决定用我聪明的大脑考虑所有情况并用 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 的多次审核和指导,求通过!
Blog by cloud_eve is licensed under CC BY-NC-SA 4.0