Advent Calendar Contest 2020 - yukicoder - 12/01
この記事は Advent Calendar Contest Advent Calendar 2020 に出題された問題の解いた記録です. 半分解説, 半分メモくらいの質を目指します. また私の実力的に星3になると解けるかだいぶ怪しいです. 公式に 「 解説は公開時間の23.5時間後に公開します。」 とありますので, これを目安に公開するようにします.
2020/12/01 - No.1304 あなたは基本が何か知っていますか?私は知っています.
DP 解法
2つの問題の複合になっていて,
- 2つ同じものが並ばないような数の並びは何通りあるか
- 総xor和が狙った数になるような数の組合わせは何通りあるか
という問題を同時に解く. そして, これらはともにDPで解ける.
さて, 明らかに気になる点があって,
- 各要素
は 0 以上 1024 未満なのでその総xor和も 0 以上 1024 未満A_i -
がやたらに大きな数が許されているが, 実際には区間X,Y との積を取ったその範囲だけ見れば良い[0, 1024)
-
- 数列
の数の重複は取り除いたほうが良いA - (直接に言及されていないが)異なる添字から取ってきても同じ数なら同じ数列と数えそうなので, 重複は最初に取り除いてから扱うほうが良さそう
他に気になる点は本当はあるけど, DP 解法ではここまでで良い.
2つ同じものが並ばないような数の並びは何通りあるか
長さ
とすると,
dp_0^x = \begin{cases}1 & \text{ if } x \in A,\\0 & \text{ otherwise } \end{cases} dp_{i+1}^x = \begin{cases} \sum_z dp_i^z - dp_i^x & \text{ if } x \in A,\\0 \end{cases}
という漸化式が組み立てられる.
ただし2式目の更新で
遅くないなら分かりやすいしそのまま書いてもいいけど, 今回は遅い.
別途
更新式はもちろん,
\overline{dp}_{i} = \sum_z dp_i^z
総xor和が狙った数になるような数の組合わせは何通りあるか
xor の演算子を
dp_0^x = \begin{cases}1 & \text{ if } x \in A,\\0 & \text{ otherwise } \end{cases} dp_{i+1}^{z} = \sum_z \sum_{x \in A} dp_i^{z \oplus x}
複合バージョン
以上2つを組み合わせれば,
これを計算すればいい. コレと一緒に,
も持っておくと便利.
更新式は次の通り.
- 初期化
dp_0^{x,x} = \overline{dp}_0^x = 1 ~ \text{ if } x \in A
- 更新
dp_{i+1}^{z,x} = \sum_z \overline{dp}_i^{z \oplus x} - dp_i^{{z \oplus x},x} \overline{dp}_{i+1}^z = \sum_z \sum_{x \in A} \overline{dp}_i^{z \oplus x} - dp_i^{{z \oplus x},x}
注意として,
さてこの更新は, 全体で
今回は計算時間は大丈夫だったが, 三次元配列でこれを全部持つとメモリのほうがオーバーしてしまった(私の場合はかなり冗長な ModInt をこれに載せてたので)ので, 節約する必要があった.
半分全列挙 (TLE)
これを書いてて気づいたが,
N \leq 40 -
が偶数!N K^N \leq 2 \times 10^{15}
如何にも半分全列挙しろと言っている.
-
通りの数列を全て作るK^m - この中で同じ数が2つ並んでるものは予め省く
- それぞれの総xor和
をメモするS - 一番末尾の数
をメモするB
中で同じのが2つ並んでないかチェックの必要はあるので, そこに毎回
最終的に出来上がる
を二次元配列とかで記録しておく.
さて前半の
-
S \oplus S' = x \iff S' = S \oplus x
B' \ne B
ただし,
TLE した. 半分を列挙するところが間に合ってないんじゃないかと睨んでる.
その中でDPするとか工夫の余地はあるけれど, もはや半分全列挙する意義とはとなる. これは引っ掛け用に用意した制約?
Discussion