「Gym-102803H」Hate That You Know Me
题目概述
给定 \(a, b, n\) ,\(a, b \in \{0, 1, 2, 3\} ,n \leq 10^{12}\) ,求
思路&&做法
首先观察到题目需要求从 \(1\) 到 \(n\) 的每个数的因数的 \(k\) 次方和,对于这种题,我们有一个思考方向是考虑计算贡献。
可以发现对于 \(x\) ,它会在它的倍数的地方计算一次贡献,假设当前是求 \(k\) 次方,则 \(x\) 的贡献就是 $x^k \times \left \lfloor \frac{n}{x} \right \rfloor $ 。
但我们显然不能枚举 \(x\) ,所以要思考怎么计算这个式子。结合式子中的向下取整以及 \(n \leq 10^{12}\) 的范围,我们可以联想到整除分块,对于整除分块,我们可以分出 \(O(\sqrt{n})\) 个 $ \left \lfloor \frac{n}{x} \right \rfloor $相等的块,并且每个块中的 \(x\) 是连续的,假设某一个块的区间是 \([l, r]\) ,该区间的贡献即 \(\left \lfloor \frac{n}{x} \right \rfloor \times \sum_{i = l}^r i^k\) ,注意到本题 \(a, b \le 3\) ,所以是有区间 \(k\) 次方和的公式的,这时我们只需动动小手,上网一查即可。
- \(\sum_{i = l}^{r} i^0 = r - l + 1\)
- \(\sum_{i = l}^{r} i^1 = \frac{(r + l) \times (r - l + 1)}{2}\)
- \(\sum_{i = 1}^{n} i^2 = \frac{n \times (n + 1) \times (2n + 1)}{6}\)
- \(\sum_{i = 1}^{n} i^3 = (\frac{n \times (n + 1)}{2})^2\)
对于 \(k\) 次方和,有兴趣可以看下这篇博客
/*
address:https://vjudge.net/problem/Gym-102803H
*/
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e6 + 5;
int a, b;
ULL n;
inline ULL calc(ULL l, ULL r, int x) {
if (x == 0) return r - l + 1;
if (x == 1) return (l + r) * (r - l + 1) / 2;
if (x == 2) return (r * (r + 1) * (2 * r + 1) / 6) - ((l - 1) * (l) * (l * 2 - 1) / 6);
if (x == 3) return (r * (r + 1) / 2) * (r * (r + 1) / 2) - (l * (r - 1) / 2) * (l * (r - 1) / 2);
}
int main() {
scanf("%d%d%llu", &a, &b, &n);
ULL x = 0, y = 0;
for (ULL L = 1, R = 1;n / L;L = R + 1) {
R = n / (n / L);
x += calc(L, R, a) * (n / L);
y += calc(L, R, b) * (n / L);
}
printf("%llu", x ^ y);
return 0;
}
完结撒花……了吗?
如果此时你交一发,会发现自己神奇的 \(\text{WA}\) 在了第 \(3\) 个点。
仔细观察,代码中计算的部分是有除法的,在取模的情况下不能进行除法,然后我们又悲催地发现模数不是质数,还不保证互质,所以乘法逆元不可行。但我们知道,是在乘完取模后不能除,而我们在除的时候是在计算一个固定值,并不是边乘边取,所以我们可以在乘上两个数取模之前先把要除的数除掉就行。
/*
address:https://vjudge.net/problem/Gym-102803H
AC 2025/2/8 14:53
*/
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e6 + 5;
int a, b;
ULL n;
inline ULL calc(ULL l, ULL r, int x) {
ULL ret = 1;
if (x == 0) return r - l + 1;
if (x == 1) {
ULL x = l + r, y = r - l + 1;
if (!(x & 1)) x /= 2;
else y /= 2;
return x * y;
}
if (x == 2) {
ULL x = r, y = r + 1, z = 2 * r + 1;
if (x % 2 == 0) x /= 2;
else if (y % 2 == 0) y /= 2;
else z /= 2;
if (x % 3 == 0) x /= 3;
else if (y % 3 == 0) y /= 3;
else z /= 3;
ret = x * y * z;
x = l - 1, y = l, z = l * 2 - 1;
if (!(x & 1)) x /= 2;
else if (!(y & 1)) y /= 2;
else z /= 2;
if (x % 3 == 0) x /= 3;
else if (y % 3 == 0) y /= 3;
else z /= 3;
ret -= x * y * z;
return ret;
}
if (x == 3) {
if (r & 1) ret = ((r + 1) / 2) * ((r + 1) / 2) * r * r;
else ret = (r / 2) * (r / 2) * (r + 1) * (r + 1);
ULL del;
if (l & 1) del = ((l - 1) / 2) * ((l - 1) / 2) * l * l;
else del = (l / 2) * (l / 2) * (l - 1) * (l - 1);
ret -= del;
return ret;
}
}
int main() {
scanf("%d%d%llu", &a, &b, &n);
ULL x = 0, y = 0;
for (ULL L = 1, R = 1;n / L;L = R + 1) {
R = n / (n / L);
x += calc(L, R, a) * (n / L);
y += calc(L, R, b) * (n / L);
}
printf("%llu", x ^ y);
return 0;
}
这道题不难,就是中间要在取模前除有点坑。

浙公网安备 33010602011771号