2020年5月11日月曜日

CodeChef May Challenge 2020 - Binary Land

11が書いてあるマスから11が書いてあるマスへのパスの求め方だけ検討すればよい。

2地点間のパスの総数自体は単純なDPで求まる。DPの遷移はN×NN \times Nの行列で書けるので、行列積をセグメント木などに乗せればO(N3QlogQ){O}(N^3Q\log Q)で解ける。また、クエリが単調なことを利用するとSWAGが使えてO(N3Q){O}(N^3Q)になる。

満点を取るためにはもう少し頑張る必要がある。まず、遷移の行列が三重対角行列になっていることに注目すると、行列積はO(N2){O}(N^2)になる。したがって、SWAGへのpushとpopはこの計算量でできる……が、三重対角行列同士の積が三重対角行列になるわけではないので、SWAGをfoldする時の掛け算はどうしてもO(N3){O}(N^3)になってしまう。しかし、pathクエリに対して必要なのは行列そのものではなく一点の値なので、そこだけ求めるのはO(N){O}(N)で可能だった。これでO(N2Q){O}(N^2Q)になった。

これでもなかなかACできなかった。行列をなるべく陽に持たずに省略できる部分は省略して、定数倍高速化を徹底するとようやく通った。