可以想到将
d
d
d函数的前缀和转化一下:
S
d
(
i
)
=
∑
i
=
1
n
d
(
i
)
=
∑
i
=
1
n
⌊
n
i
⌋
S_d(i)=\sum_{i=1}^n d(i)=\sum_{i=1}^n \left\lfloor\frac{n}{i}\right\rfloor
Sd(i)=i=1∑nd(i)=i=1∑n⌊in⌋
那么就可以求出
O
(
n
)
O(\sqrt{n})
O(n)求出每一个前缀和了(整除分块),加上一个unordered_map
去除不必要的计算。
将问题修改一下: i ≤ n , j ≤ m ⟶ i < n + 1 , j < m + 1 i \leq n, j \leq m \longrightarrow i < n + 1, j < m + 1 i≤n,j≤m⟶i<n+1,j<m+1
接下来解决 x o r \mathrm{xor} xor的问题,首先可以发现,我们可以转化一下问题,求出每一个 d ( i ) d(i) d(i)的贡献。可以(比较难)想到使用数位 d p dp dp的思想,设定前面几位是相同的,然后固定某一位比原数小,然后后面的所有位随便放。
这里设定 l e n a , l e n b , a , b len_a, len_b, a, b lena,lenb,a,b,其中 a a a的后 l e n a len_a lena是随便放的,强制令 a a a是第 0 0 0到 l e n a − 1 len_a-1 lena−1都是 0 0 0, 第 l e n a len_a lena位比 n n n小(只能是 0 0 0了),然后 l e n a len_a lena(含)之后的位都和 n n n相同, l e n b , b len_b, b lenb,b同理。
设 m x = max { l e n a , l e n b } , m n = min { l e n a , l e n b } mx=\max\{len_a, len_b\}, mn=\min\{len_a, len_b\} mx=max{lena,lenb},mn=min{lena,lenb},一个数 n u m num num的二进制第 p p p位是 n u m p num_p nump。
那么可以发现,对于
m
x
mx
mx(含)之后的位,都是可以确定的(废话),使用题目的公式计算出来就好了,我们设计算出的结果是
p
r
e
pre
pre。那么公式可以是:
p
r
e
=
a
∧
b
∧
x
∧
¬
2
m
x
pre=a \land b \land x \land \lnot2^{mx}
pre=a∧b∧x∧¬2mx
但是对于第
1
1
1到
m
x
−
1
mx-1
mx−1的位,可以不管题目提供的
x
x
x,因为任何一种可能都能够配出来。设一种可能为
v
a
l
val
val,考虑第
p
p
p位,若
p
>
m
n
p>mn
p>mn,那么只有一种可能,就是在
l
e
n
len
len的那个数(现在假设为
l
e
n
a
len_a
lena较大)中配一个
v
x
o
r
x
p
x
o
r
b
p
v~\mathrm{xor}~x_p~\mathrm{xor}~b_p
v xor xp xor bp。假设
p
≤
m
n
p\leq mn
p≤mn,那么就有两种可能:
v
x
o
r
x
p
=
a
p
x
o
r
b
p
v~\mathrm{xor}~x_p=a_p~\mathrm{xor}~b_p
v xor xp=ap xor bp。那么对于任何一种可能,都有
2
m
n
2^{mn}
2mn种
a
,
b
a,b
a,b的配合情况。所有的可能就是
[
p
r
e
,
p
r
e
+
2
m
x
−
1
]
[pre,pre+2^{mx}-1]
[pre,pre+2mx−1]中的整数了。那么一组
l
e
n
a
,
l
e
n
b
,
a
,
b
len_a, len_b, a, b
lena,lenb,a,b的答案就是:
a
n
s
(
l
e
n
a
,
l
e
n
b
,
a
,
b
)
=
(
S
d
(
p
r
e
+
2
m
x
−
1
)
−
S
d
(
p
r
e
−
1
)
)
×
2
m
n
ans(len_a, len_b, a, b)=\left(S_d\left(pre+2^{mx}-1\right)-S_d(pre-1)\right)\times 2^{mn}
ans(lena,lenb,a,b)=(Sd(pre+2mx−1)−Sd(pre−1))×2mn
那么最终答案就是所有合法的
l
e
n
a
,
l
e
n
b
,
a
,
b
len_a, len_b, a,b
lena,lenb,a,b答案之和了。
PS:记得想要得到一个
2
p
(
p
>
31
)
2^p(p>31)
2p(p>31),必须要写1ll<<p
,而不是1<<p
。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL MOD = 998244353;
unordered_map<LL, LL> mp;
LL n, m, vl;
LL calc_sd(LL n) {
if (n < 0) return 0;
if (mp.count(n)) return mp[n];
LL ans = 0;
for (LL l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
ans = (ans + (r - l + 1) * (n / l) % MOD) % MOD;
}
return mp[n] = ans;
}
LL calc_ans(LL x, LL y, LL lx, LL ly) {
if (lx > ly) swap(x, y), swap(lx, ly);
LL pre = (x ^ y ^ vl) & (~((1ll << ly) - 1));
LL val1 = calc_sd(pre + (1ll << ly) - 1), val2 = calc_sd(pre - 1);
return (val1 - val2 + MOD) % MOD * (1ll << lx) % MOD;
}
int main() {
scanf("%lld%lld%lld", &n, &m, &vl), n++, m++;
LL ans = 0;
for (int i = 0; i <= 50; i++) if (n & (1ll << i))
for (int j = 0; j <= 50; j++) if (m & (1ll << j))
ans = (ans + calc_ans(n ^ (1ll << i), m ^ (1ll << j), i, j)) % MOD;
printf("%lld\n", ans);
return 0;
}