Describtion
以二进制给定一整数 L L L ,求有多少二元组 ( a , b ) (a,b) (a,b) 满足 a + b = a ⊕ b ≤ L a+b=a\oplus b\leq L a+b=a⊕b≤L 。
Solution
对
a
,
b
a,b
a,b 的二进制形式的每一位进行讨论。
因为异或是不进位加法,所以
a
+
b
=
a
⊕
b
a+b=a\oplus b
a+b=a⊕b 相当于
a
a
a 和
b
b
b 的同一位不能同为
1
1
1。
令
d
p
[
i
]
[
0
]
dp[i][0]
dp[i][0] 为
a
⊕
b
a\oplus b
a⊕b 的前
i
i
i 位小于
L
L
L 的前
i
i
i 位的方案数,
d
p
[
i
]
[
1
]
dp[i][1]
dp[i][1] 则为等于的方案数。
- L L L 的当前位为 1 1 1。此时等于的情况为上一位等于且 a , b a,b a,b 分别取 1 , 0 1,0 1,0 和 0 , 1 0,1 0,1,即 d p [ i ] [ 1 ] = d p [ i − 1 ] [ 1 ] × 2 dp[i][1]=dp[i-1][1]\times2 dp[i][1]=dp[i−1][1]×2。小于的情况有两种:上一位小于,则有 3 3 3 种情况: 0 , 0 0,0 0,0, 0 , 1 0,1 0,1和 1 , 0 1,0 1,0 ;上一位等于的情况就 1 1 1 种: 0 , 0 0,0 0,0,即 d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] × 3 + d p [ i − 1 ] [ 1 ] dp[i][0]=dp[i-1][0]\times3+dp[i-1][1] dp[i][0]=dp[i−1][0]×3+dp[i−1][1]。
- L L L 的当前位为 0 0 0。等于的情况为上一位等于且 a , b a,b a,b 都取 0 0 0,即 d p [ i ] [ 1 ] = d p [ i − 1 ] [ 1 ] dp[i][1]=dp[i-1][1] dp[i][1]=dp[i−1][1]。小于的情况只有 3 3 3 种,即上一位小于, a , b a,b a,b 分别取 0 , 0 0,0 0,0, 0 , 1 0,1 0,1和 1 , 0 1,0 1,0。
最终答案即为 d p [ n ] [ 1 ] + d p [ n ] [ 0 ] dp[n][1]+dp[n][0] dp[n][1]+dp[n][0], n n n即为 L L L的二进制长度。
Code
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
long long n,dp[105000][2];
char s[105000];
int main(){
scanf("%s",s+1);
n=strlen(s+1);
dp[0][1]=1;//初始化
for(int i=1;i<=n;++i){
dp[i][0]=(dp[i-1][0]*3)%mod;
if(s[i]=='1'){
dp[i][0]=(dp[i][0]+dp[i-1][1])%mod;
dp[i][1]=(dp[i-1][1]*2)%mod;
}
else dp[i][1]=dp[i-1][1];
}
printf("%lld\n",(dp[n][0]+dp[n][1])%mod);
return 0;
}