[题解][LG-P3791]普通数学题

可以想到将 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=1nd(i)=i=1nin
那么就可以求出 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 in,jmi<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 lena1都是 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=abx¬2mx

但是对于第 1 1 1 m x − 1 mx-1 mx1的位,可以不管题目提供的 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 pmn,那么就有两种可能: 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+2mx1]中的整数了。那么一组 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+2mx1)Sd(pre1))×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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值