AtCoder Regular Contest 141 - B - Increasing Prefix XOR
原文
Consider the problem in binary.
If positive integers \(a\) and \(b\) have the same number of digits, the only case when both \(a<c\) and \(b < b\oplus c\) hold is when \(c\) has more digits than each of \(a\) and \(b\), in which case \(c\) and \(b \oplus c\) have the same number of digits.
From this, it can be inductively shown that when \(A\) satisfies the conditions, \(A_{i+1}\) has more digits than \(A_i\). On the other hand, if \(A_{i+1}\) has more digits than \(A_i\) for every \(i\), the conditions are obviously satisfied.
Therefore, when \(M < 2^{60}\), the answer is \(0\) if \(60 < N\). Otherwise, let us precompute the number of \(k\)-digit integers between \(1\) and \(M\) to solve the problem in \(O(N\log^2 M)\) time by dynamic programming, where we set
\(dp[n][k]:\) the number of sequences \((A_1,\ A_2,\ \dots,\ A_n)\) of positive integers with increasing numbers of digits whose \(A_n\) has \(k\) digits.
(Alternatively, consider taking at most one \(k\)-digit integer for each \(k\) to choose \(N\) in total, to solve it in \(O(N \log M)\) time.)
Therefore, the problem can be solved in \(O(\log^3{M})\) or \(O(\log^2 {M})\) time.
解释:
我们从二进制的角度来解决这个问题。
如果两个正整数a,b在二进制下有相同的位数,若希望\(a<c\) 和 \(b < b\oplus c\) 均成立,只有\(c\)的位数比\(a,b\)都多才能满足。在这种情况下,\(c\) 和 \(b \oplus c\) 的位数是相同的。
换句话说,若\(a<c\) 和 \(b < b\oplus c\) 均成立,则必有\(c\)的位数比\(a,b\)都多(注意前提条件,a,b的位数相同)。
为什么呢?
从右式出发,显然c的位数不可能小于b,假设c的位数和b相同,均为\(n\)。
显然它们的最高位必然均为1,则异或的结果的位数必然小于\(n\),故\(b > b \oplus c\),与原条件矛盾,故假设不成立。
故\(c\)的位数大于\(a,b\)的位数
由此,当序列\(A\)满足条件时,有\(A_{i+1}\)的位数多于\(A_i\)。另一方面,如果\(A_{i+1}\)的位数均大于\(A_i\),则显然能满足条件。
这里相当于令上文的\(a = A_i, b = B_i, c = A_{i + 1}\)
需要补充说明:
- 原条件:\(B_1<B_2<⋯<B_N, \text {where } B_i = A_1 \oplus A_2 \oplus \dots \oplus A_i.\)
- \(B_i的位数 = A_i的位数,即b = a\) 的必要条件是\(A_{i+1}\)的位数均大于\(A_i\)
- \(B_{i + 1}= B_i \oplus A_{i+ 1}\)
- \(A_i = B_i\oplus A_1 \oplus A_2 \oplus ...\oplus A_{i - 1}\)
因此,当\(M<2^{60}\)时,如果\(N > 60\),答案就是\(0\)。
\(A_i\)的位数是单调递增的,若\(N > 60\),则必存在\(A_i,A_i\)的位数\(>60\),而条件限制\(A_i\le M\),显然有矛盾,故答案为0
否则,让我们预先计算\(1\)到\(M\)之间的长度为\(k\)(二进制下)的整数的个数,通过动态规划在\(O(Nlog^2 M)\)的时间内解决这个问题,其中我们设定
\(dp[n][k]:\)由位数单调递增的正整数组成的,长度为n的序列\((A_1,\ A_2,\ \dots,\ A_n)\)构成的集合的元素个数,且其中\(A_n\)有\(k\)位数。
\(dp(n, k) = cnt[k]* \sum_{j=1}^{k-1}dp(i-1, j)\),其中
cnt[k]
为位数为k
的整数的数量
(或者,考虑在每一个\(k\)中最多取一个\(k\)位数的整数,总共选择\(N\)次,以\(O(N\log M)\)的时间来解决。)
Alternatively, consider taking at most one \(k\)-digit integer for each \(k\) to choose \(N\) in total, to solve it in \(O(N \log M)\) time.
这里实在看不太明白==
因此,这个问题可以在\(O(\log^3{M})\)或\(O(\log^2 {M})\)时间内解决。
代码
// Problem: B - Increasing Prefix XOR
// Contest: AtCoder - AtCoder Regular Contest 141
// URL: https://atcoder.jp/contests/arc141/tasks/arc141_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 61, mod = 998244353;
typedef long long LL;
LL n, m, ans;
int f[N][N];
LL cnt[N];
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
int size = 0;
LL t = m;
while (t){
size ++ ;
t >>= 1;
}
for (int i = 1; i <= 60; i ++ ){ // cnt[i]表示位数为 i 的,不超过 m 的整数的个数
if (i < size) cnt[i] = 1ll << (i - 1);
if (i == size) cnt[i] = m + 1 - (1ll << (i - 1));
if (i > size) break;
f[1][i] = cnt[i];
}
if (n > 60){
cout << "0" << endl;
return 0;
}
for (int i = 2; i <= n; i ++ ){ // 长度
for (int j = 1; j <= size; j ++ ){ // A_n的位数
for (int k = 1; k < j; k ++ ){ // A_(n-1)的位数
f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
}
f[i][j] = cnt[j] % mod * f[i][j] % mod;
}
}
for (int i = 0; i <= 60; i ++ ) ans = (ans + f[n][i]) % mod;
cout << ans << endl;
return 0;
}
疑惑
我想用前缀和优化一维,但是改来改去还是wa:(