trsing’s diary

勉強、読んだ本、仕事で調べたこととかのメモ。

diverta 2019 Programming Contest E: XOR Partitioningメモ

atcoder.jp

うっかりE問題を見てしまい1週間うんうん唸り続ける羽目になったけどようやくなんとなくわかったのでメモ。公式解説のほかいろいろ見た。問題名でググって出てくるとこは大体目を通しましたよと。もはやどれを参考にできたかも覚えておらぬ。

解説の流れ

https://img.atcoder.jp/diverta2019/editorial.pdf

0,1,..,N+1の番号がついたN個のマスが左から右に向かって並んでいる。 マスiには整数b_{i}が書かれている。 すぬけ君ははじめに好きな整数Xを任意に選んだのち、駒をマス0に置く。 その後、以下のルールで駒を動かす。

  • 現在駒が置かれているマスより、番号が大きいマスにしか動かせない
  • 現在駒が置かれているマスに0が書かれているなら、Xが書かれているマスに駒を移動させなくてはならない
  • 現在駒が置かれているマスにXが書かれているなら、0が書かれているマスに駒を移動させなくてはならない

最終的に駒がマスNに置かれているように駒を動かす方法は何通りあるか?

与えられた数列をA、各要素をa_{i}, 1\leq i \leq Nとおく。
a_{i}の累積xorの数列をB、各要素をb_{i}, 1\leq i\leq Nとおく。
与えられた数列を分割して作成した数列をC_{i}, 1\leq i\leq k、 数列C_{i}の要素をc_{ij}, 1 \leq j \leq lとおく。下図みたいな感じ。
f:id:trsing:20190519135624g:plain

ある値XC_{i}たちの美しさが全て等しくなるとする。このとき、

C_{i}の要素に対してxorを取るとX
C_{i}に対して累積xorを取るとC_{1}=b_{d}=X,C_{1}\oplus C_{2}=b_{e}=0,C_{1}\oplus C_{2}\oplus C_{3}=b_{f}=Xと、X,0が交互に並ぶ形になる。

Bの要素からX0に注目し、交互に並ぶように選べば美しさが等しい分割となる。
f:id:trsing:20190519160046p:plain

簡単のためb_{N}0でない場合を考えます。このときはXが一意に定まります。

\oplus_{i=1}^{k}C_{i}=\oplus_{i=1}^{N}a_{i}=b_{N}だからb_{N}= 0 or X
b_{N}\neq0ならX=b_{N}Xが一意に定まる。

f:id:trsing:20190519140209p:plain

0/Xの遷移に加え、前の値の代わりに自分の値を使えるということだろう(あまり理解してない)
f:id:trsing:20190519151615p:plain

X= 0の場合は特殊ですが、容易に計算可能です。

値が0b_{i}の数がn個とすれば2^{n-1} (単に仕切りをどこにいれるかという話)。

bX0以外の数を取り除いたのち、ランレングス圧縮を行った数列における0の出現回数はbにおけるXの出現回数で抑えられることが重要です。

0Xに隣接していることになるので、圧縮すればせいぜいXの出現数+1

b_{i}= 0なるiに関する遷移をうまく遷移をまとめると

うまくまとめる・・・
f:id:trsing:20190519141517p:plain

ここで詰んだので他の解説やらを探すと次の方のコードおよび解説のおかげでなんとなくわかりました。ありがとうございます。

Submission #5380934 - diverta 2019 Programming Contest

自分の理解は次のようになります。あってるかどうかは知らぬ。

dp[j]からdp[i]への影響は途中にある0の個数による。 f:id:trsing:20190519151656p:plain
漸化式は
\displaystyle{
dp[i]=1+\sum_{j=0}^{i-1}\left( \sum_{k=j}^{i-1}z[k] \right)dp[j]\\ \hspace{20pt}=
1+\sum_{j=0}^{i-2}\left( \sum_{k=j}^{i-1}z[k] \right)dp[j]+z[i-1]dp[i-1]\\ \hspace{20pt}=
1+\sum_{j=0}^{i-2}\left( \sum_{k=j}^{i-2}z[k] + z[i-1] \right)dp[j]+z[i-1]dp[i-1]\\ \hspace{20pt}=
1+\sum_{j=0}^{i-2}\left( \sum_{k=j}^{i-2}z[k] \right) dp[j]+ z[i-1]\sum_{j=0}^{i-2} dp[j]+z[i-1]dp[i-1]\\ \hspace{20pt}=
dp[i-1]+z[i-1]\sum_{j=0}^{i-1} dp[j]
}
※最初の1は初手でiを選ぶ場合

上手く計算(dpの累積和、区間0の個数を記録しておく)すればO(bにおけるXの出現回数)。それぞれのXの出現回数の総数はNなので全体としてO(N)となる。

次のようにしてb_{i},b_{j}区間0の数を出せるようにしておけば使いまわせる。
f:id:trsing:20190519151936p:plain

所感

難しい・・・とても難しい・・・。考え方がわかってたとしても時間内に終わる気しねえ・・・。