题意:
给定一个二进制表示的数
n
n
n,问有多少对自然数
(
x
,
y
)
(x,y)
(x,y) 满足
x
+
y
⩽
n
x+y \leqslant n
x+y⩽n且
x
+
y
=
=
x
⊕
y
x+y==x \oplus y
x+y==x⊕y。
思路:
这是一道数位
d
p
dp
dp。
由于异或是无进位相加,所以
x
+
y
=
=
x
⊕
y
x+y==x \oplus y
x+y==x⊕y 等价于
x
x
x 和
y
y
y 转化为二进制之后,每一位都不会出现两个
′
1
′
'1'
′1′。
设
x
i
x_{i}
xi 表示
x
x
x 的二进制表示形式的第
i
i
i 位。
首先考虑一下特殊情况,如果 n n n的二进制表示形式全部是都是由 ′ 1 ′ '1' ′1′组成的,那么可以想象到, x , y , x + y x,y,x+y x,y,x+y 均 ⩽ n \leqslant n ⩽n,即对于 i ( 1 ⩽ i ⩽ l e n g t h ( n ) ) i(1 \leqslant i \leqslant length(n)) i(1⩽i⩽length(n)),都可能出现 x i = = 0 & y i = = 0 ( { 0 , 0 } ) x_{i}==0\&y_{i}==0 (\{0,0\}) xi==0&yi==0({0,0})、 x i = = 1 & y i = = 0 ( { 1 , 0 } ) x_{i}==1\&y_{i}==0 (\{1,0\}) xi==1&yi==0({1,0})、 x i = = 0 & y i = = 1 ( { 0 , 1 } ) x_{i}==0\&y_{i}==1 (\{0,1\}) xi==0&yi==1({0,1}) 这三种情况,因此 ( x , y ) (x,y) (x,y) 总共有 3 l e n g t h ( n ) 3^{length(n)} 3length(n) 种。
但是如果
n
n
n的二进制表示形式中有
′
0
′
'0'
′0′的话就会比较难办了,因为
3
l
e
n
g
t
h
(
n
)
3^{length(n)}
3length(n) 种情况中必然有一些使
x
+
y
>
n
x+y>n
x+y>n 等不合法的自然数对出现。 既然这样,我们只需要将
x
+
y
<
n
x+y<n
x+y<n 和
x
+
y
=
n
x+y=n
x+y=n 的情况均求出来即可。
设
d
[
i
]
[
0
]
d[i][0]
d[i][0] 表示
(
x
+
y
)
j
=
=
n
j
(
1
⩽
j
⩽
i
)
(x+y)_{j}==n_{j}(1\leqslant j \leqslant i)
(x+y)j==nj(1⩽j⩽i) 的情况数,
d
[
i
]
[
1
]
d[i][1]
d[i][1] 表示
1
⩽
j
⩽
i
1\leqslant j \leqslant i
1⩽j⩽i 中存在至少一位
j
j
j,使得
(
x
+
y
)
j
<
n
j
(x+y)_{j}<n_{j}
(x+y)j<nj 的情况数。
那么当
n
i
=
1
n_{i}=1
ni=1 时,对于相等的情况,有
{
1
,
0
}
、
{
0
,
1
}
\{1,0\}、\{0,1\}
{1,0}、{0,1} 这两种可能,因此
d
[
i
]
[
0
]
=
d
[
i
−
1
]
[
0
]
∗
2
d[i][0]=d[i-1][0]*2
d[i][0]=d[i−1][0]∗2 ;而对于小于的情况,可以是前
i
−
1
i-1
i−1位小于的方案数
∗
3
*3
∗3,表示
{
0
,
0
}
、
{
1
,
0
}
、
{
0
,
1
}
\{0,0\}、\{1,0\}、\{0,1\}
{0,0}、{1,0}、{0,1} 三种情况都合法,即
d
[
i
]
[
1
]
=
d
[
i
−
1
]
[
1
]
∗
3
d[i][1]=d[i-1][1]*3
d[i][1]=d[i−1][1]∗3;也可以是前
i
−
1
i-1
i−1位均相等的方案,再加上
{
0
,
0
}
\{0,0\}
{0,0} ,即在第
i
i
i 位时开始小于,
d
[
i
]
[
1
]
+
=
d
[
i
−
1
]
[
0
]
d[i][1]+=d[i-1][0]
d[i][1]+=d[i−1][0]。
而当
n
i
=
0
n_{i}=0
ni=0 时,小于的情况只可能是前
i
−
1
i-1
i−1位小于的方案数
∗
3
*3
∗3,
d
[
i
]
[
1
]
=
d
[
i
−
1
]
[
1
]
∗
3
d[i][1]=d[i-1][1]*3
d[i][1]=d[i−1][1]∗3,而等于也只有
{
0
,
0
}
\{0,0\}
{0,0} 一种情况,
d
[
i
]
[
0
]
=
d
[
i
−
1
]
[
0
]
d[i][0]=d[i-1][0]
d[i][0]=d[i−1][0]。
注意初始化时,
d
[
1
]
[
0
]
=
1
,
d
[
1
]
[
1
]
=
0
d[1][0]=1,d[1][1]=0
d[1][0]=1,d[1][1]=0。
下面代码中
d
[
i
]
[
0
]
d[i][0]
d[i][0] 表示为
r
e
s
res
res、
d
[
i
]
[
1
]
d[i][1]
d[i][1] 表示为
c
n
t
cnt
cnt。
时间复杂度: O ( n ) O(n) O(n)
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int main() {
string n;
cin >> n;
long long res = 1, cnt = 0;
for (long long i = 0; i < n.size(); i++) {
cnt = (cnt * 3) % mod;//d[i][1]=d[i-1][1]*3
if (n[i] == '1') {
cnt = (cnt + res) % mod;//d[i][1]+=d[i-1][0]
res = (res * 2) % mod;//d[i][0]=d[i-1][0]*2
}
}
cout << (res + cnt) % mod;//d[length(n)][0]+d[length(n)][1]
return 0;
}