AT2272 [ARC066B] Xor Sum
https://www.luogu.com.cn/problem/AT2272
首先要注意到xor是不进位的加法
所以加法可以表示成
a
+
b
=
(
a
⊕
b
)
+
(
(
a
&
b
)
<
<
1
)
a+b=(a\oplus b)+((a\&b)<<1)
a+b=(a⊕b)+((a&b)<<1)
可以得到
a
+
b
≥
a
⊕
b
a+b\ge a\oplus b
a+b≥a⊕b
假设
a
≤
b
a\le b
a≤b
那么我们考虑设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示考虑
a
,
b
a,b
a,b的前
i
i
i为,和为
j
j
j的方案数
那么转移这一位有3种情况
(
0
,
0
)
(
0
,
1
)
(
1
,
1
)
(0,0)(0,1)(1,1)
(0,0)(0,1)(1,1)
对应状态转移为
- j − > 2 j j->2j j−>2j
- j − > 2 j + 1 j->2j+1 j−>2j+1
- j − > 2 ( j + 1 ) j->2(j+1) j−>2(j+1)
把这个翻过来就可以得到方程
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
2
]
+
f
[
i
−
1
]
[
j
−
1
2
]
+
f
[
i
−
1
]
[
j
−
2
2
]
f[i][j]=f[i-1][\frac{j}{2}]+f[i-1][\frac{j-1}{2}]+f[i-1][\frac{j-2}{2}]
f[i][j]=f[i−1][2j]+f[i−1][2j−1]+f[i−1][2j−2]
然后把第一维滚掉就是一个 O ( l o g n ) O(log n) O(logn)的递归式了
code:
#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
ll n;
map<ll, ll> f;
ll dp(ll n) {
if(f.find(n) != f.end()) return f[n];
return f[n] = (dp(n / 2) + dp((n - 1) / 2) + dp(n / 2 - 1)) % mod;
}
int main() {
f[0] = 1, f[1] = 2;
scanf("%lld", &n);
printf("%lld", dp(n));
return 0;
}