题意
给定 N N N(以二进制的形式给出),求满足 x , y ∈ [ 0 , N ] x,y \in [0,N] x,y∈[0,N],且 x ⊕ y = x ∣ y x \oplus y = x \,|\, y x⊕y=x∣y 的数对 ( x , y ) (x,y) (x,y) 的个数(对 998244353 998244353 998244353 取模)。
思路
(下文中 N , x , y N,x,y N,x,y 等,若不加说明,指的是其二进制。)
比较按位异或和按位与的运算法则,不难发现,对于 x \pmb x x 和 y \pmb y y 的(二进制的)第 i \pmb i i 位 x i , y i \pmb{x_i,y_i} xi,yi,有 ( x i , y i ) = ( 0 , 0 ) or ( 0 , 1 ) or ( 1 , 0 ) \pmb{(x_i,y_i) = (0,0) \text{ or } (0,1) \text{ or } (1,0)} (xi,yi)=(0,0) or (0,1) or (1,0),不能为 ( 1 , 1 ) \pmb{(1,1)} (1,1)。
如果 N = 11 … 1 ⏟ n 个 N=\underbrace{11\dots1}_{n个} N=n个 11…1,那么对于每一位, ( x i , y i ) (x_i,y_i) (xi,yi) 都有 3 3 3 种取值,答案为 3 n 3^n 3n。(样例中 27 27 27 的来源)
如果有 0 0 0,那么数对个数就没有这么多了,因为需要保证 x , y ⩽ N x,y \leqslant N x,y⩽N。
例子
先举个例子: N = 100 N=100 N=100:从高位开始,如果 ( x 0 , y 0 ) = ( 1 , 0 ) (x_0,y_0)=(1,0) (x0,y0)=(1,0),那么对于后面两位, x 1 , x 2 x_1,x_2 x1,x2 只能取 0 0 0,而 y 1 , y 2 y_1,y_2 y1,y2 则无限制。
为什么从高位开始?简单来说,比大小是从高位比的,如果 x x x 最高位比 N N N 小,那么 x x x 一定比 N N N 小,前一位将确定性地影响后面的选择。进一步联想到,比大小中这一位相同看下一位,应该 从高位开始逐位看。
回到 N = 100 N=100 N=100,我们一位一位地看:
- 第一位是 N 0 = 1 N_0=1 N0=1:有 ans ( N 0 ) = 3 1 = 3 \operatorname{ans}(N_0)=3^1=3 ans(N0)=31=3 种取值;
- 再加上下一位, N 1 = 10 N_1=10 N1=10:第二位并不是总有 3 3 3 种取值,应该比 3 N 0 3N_0 3N0 少一些情形,具体地说,当 ( x 0 , y 0 ) = ( 1 , 0 ) (x_0,y_0)=(1,0) (x0,y0)=(1,0) 时,第二位不能取 ( 1 , 0 ) (1,0) (1,0),当 ( x 0 , y 0 ) = ( 0 , 1 ) (x_0,y_0)=(0,1) (x0,y0)=(0,1) 时,第二位不能取 ( 0 , 1 ) (0,1) (0,1),少了 2 2 2 种,因此 ans ( N 1 ) = 3 × 3 − 3 = 7 \operatorname{ans}(N_1)=3\times3-3=7 ans(N1)=3×3−3=7 种取值;
- 接着向下看, N 2 = 100 N_2=100 N2=100:它应该比 3 N 1 3N_1 3N1 少一些情形,具体地说,当 ( x 01 , y 01 ) = ( 10 , 00 ) (x_{01},y_{01})=(10,00) (x01,y01)=(10,00) 时,第三位不能取 ( 1 , 0 ) (1,0) (1,0),当 ( x 01 , y 01 ) = ( 10 , 01 ) (x_{01},y_{01})=(10,01) (x01,y01)=(10,01) 时,第三位亦不能取 ( 1 , 0 ) (1,0) (1,0),少了 2 2 2 种,当 ( x 01 , y 01 ) = ( 0 ? , 10 ) (x_{01},y_{01})=(0?,10) (x01,y01)=(0?,10) 时,也少了 2 2 2 种,共少了 4 4 4 种,因此 ans ( N 2 ) = 3 × 7 − 4 = 17 \operatorname{ans}(N_2)=3\times7-4=17 ans(N2)=3×7−4=17 种取值。
读者可以再写一些数感受一下,这里直接讨论一般情况了:
一般情况
因为是一位一位地看的,设前 i i i 位是 N 0 ∼ i N_{0\sim i} N0∼i,其答案为 ans \text{ans} ans,考虑下一位(第 i + 1 i+1 i+1 位)。
如果下一位是 1 1 1,显然 3 3 3 种取值都能取到,结果是 3 ans 3\text{ans} 3ans。
如果下一位是
0
0
0,减少的情形应该只有当
x
0
∼
i
=
N
0
∼
i
x_{0\sim i}=N_{0\sim i}
x0∼i=N0∼i(或
y
0
∼
i
=
N
0
∼
i
y_{0\sim i}=N_{0\sim i}
y0∼i=N0∼i,先讨论
x
x
x),因为此时下一位被
N
N
N 限制住了只能取
0
0
0,情形会减少;否则如果
x
x
x 的前
i
i
i 位有一位与
N
N
N 不同,下一位都是可以任意取的。
考虑
x
0
∼
i
=
N
0
∼
i
x_{0\sim i}=N_{0\sim i}
x0∼i=N0∼i,且
x
i
+
1
=
1
x_{i+1}=1
xi+1=1 时
y
y
y 的可能取值,这是不合题意的,所以这时
y
y
y 的可能取值数量就是不合题意的数量。
如果
x
0
∼
i
x_{0\sim i}
x0∼i 的某一位
x
j
x_j
xj 是
1
1
1 那么
y
j
y_j
yj 只能取
0
0
0,有一种取值,如果是
0
0
0 那么
y
j
y_j
yj 可以取
0
0
0 或
1
1
1,有两种取值,如果前
i
i
i 位有
m
m
m 个
0
0
0,依据乘法原理就有
2
m
2^m
2m 种取值,产生了
2
m
2^m
2m 种不合题意的情形,应当减去
2
m
2^m
2m。
y
0
∼
i
=
N
0
∼
i
y_{0\sim i}=N_{0\sim i}
y0∼i=N0∼i 是同理的,所以说,结果应当减去
2
×
2
m
2\times2^m
2×2m,是
3
ans
−
2
m
+
1
3\text{ans}-2^{m+1}
3ans−2m+1。
结论
记
ans
(
N
0
∼
i
)
\operatorname{ans}(N_{0\sim i})
ans(N0∼i) 表示将
N
N
N 的前
i
i
i 位作为
N
N
N 对应的数对个数,
m
i
m_i
mi 表示
N
N
N 的前
i
i
i 位中
0
0
0 的个数,有
ans
(
N
0
∼
i
)
=
{
3
,
i
=
0
3
ans
(
N
0
∼
i
−
1
)
,
i
>
0
,
N
i
=
1
3
ans
(
N
0
∼
i
−
1
)
−
2
m
i
,
i
>
0
,
N
i
=
0
\operatorname{ans}(N_{0\sim i})=\begin{cases}3, & i=0 \\3\operatorname{ans}(N_{0\sim i-1}), & i>0, N_i=1 \\3\operatorname{ans}(N_{0\sim i-1})-2^{m_i}, & i>0, N_i=0 \\\end{cases}
ans(N0∼i)=⎩
⎨
⎧3,3ans(N0∼i−1),3ans(N0∼i−1)−2mi,i=0i>0,Ni=1i>0,Ni=0
实现不难,这里就不详细解释了,直接放代码。
AC code
#include <cstdio>
#include <cstring>
#define Code int main() { int T = 1;
#define Codes int main() { int T=read();
#define by while (T--) eachT();
#define HTLDL return 0;
#define HappyHDUPKSAI }
inline long long read() { char st; long long x = 0; int fu = 1; st = getchar(); while (st > 57 || st < 48) { if (st == 45) fu = -1; st = getchar(); }while (st <= 57 && st >= 48) { x = (x << 3) + (x << 1) + st - 48; st = getchar(); }return x * fu; }
typedef long long ll;
const ll MOD = 998244353;
char s[1234567];
void eachT() {
scanf("%s", s);
int len = strlen(s);
ll ans = 1, pow = 1;
for (int i = 0; i < len; ++i) {
ans *= 3;
if (s[i] == '0') {
pow = (pow << 1) % MOD;
ans -= pow;
}
ans = (ans + MOD) % MOD;
}
printf("%lld", ans);
}
Code by HTLDL
HappyHDUPKSAI
时间复杂度 Θ ( n ) \Theta(n) Θ(n),实测 109ms \text{109ms} 109ms,最优化可达到 15ms \text{15ms} 15ms。