writer解・tester解と異なる方法で解いたので紹介します。
問題
yukicoder contest 283 G ★4.5 誕生日プレゼント
問題リンク:https://yukicoder.me/problems/no/1404
要約:
長さ N の整数列 A , B が与えられるので、次の操作を合計 P 回以下行って A を B に一致させよ。不可能ならそれを報告せよ。
- 操作 1 : i,j を選んで Ai に Aj を加算。
- 操作 2 : A の要素すべてに mod P を適用する。
制約:
- 1≤N≤105
- P=223577 ( 素数 )
- 0≤Ai,Bi<P
解説
利用する有名テクニック一覧
- ダブリング・繰り返し二乗法
- mod 素数における四則演算
- 平方分割
簡単な場合分け
操作 2 は最後に 1 回だけ行う。
A または B がすべて 0 の場合と、 N=1 の場合を排除できる。
操作 2 を最後に行うことにすれば、途中の操作 1 をすべて mod P で行うものとしてよいです。以下、操作 1 は mod P で行い、途中の操作 2 は考えません。
A がすべて 0 のとき、 B がすべて 0 なら 0 回の操作で目的が実現可能で、そうでなければ実現不可能です。逆に、 B がすべて 0 で A が「すべて 0 」ではない場合は、 B から始めて本来と逆の操作を考えると、実現不可能であることがわかります。
N=1 のとき、唯一可能な操作「 A1 に A1 を足す」を P−1 回繰り返す間に、 B に一致するか確かめます。試してみると 2(P−1)/4≡1 (mod P) より (P−1)/4 回で A1 の値が元に戻るので、操作 1 は (P−1)/4−1 回以下になります。
任意の値を 36 回の操作で生成
Ai=0 ならば、 36 回以下の操作で Aj (i=j) を任意の値にできる。
A1=0,A2=1 のとき、操作 X 「 A1 を 2 倍して、 A2 を A1 に 0 回か 1 回足す」 を K 回繰り返すと、 A1 を 0 以上 2K−1 以下の任意の整数にできます (ダブリング) 。操作はそのままで A1=s,A2=t とすると A1 を 2Ks+tx (mod P) ( x は 0 以上 2K−1 以下の整数 ) にできます。 K が P≤2K を満たし、 t=0 であれば、この値の集合は 0,1,…,P−1 (mod P) をすべて含みます。
目的の値 k のために操作の手順を復元するには x の値が必要ですが、 k=2Ks+tx を x について解くと x=(k−2Ks)/t で求まります。
2K≤P のためには K=18 でよく、操作 X は、 2 回以下の操作 1 で再現できるので、この手順全体は 36 回でできます。
値の平方分割
N が大きいとき、 N が 1 増えると操作回数が高々 2 増える。
考えられる方針は複数ありますが、値を平方分割すればうまくできます。
P≤500 を考えます。数列 A 中に 1,2,3,…,499 と 500,1000,1500,…,500×499 を出現させ、他の要素に適宜足すことで、他の要素 1 つあたり高々 2 回の操作で B と一致させられます。これを次の手順で実現します。
- A1=1,A2=1 とする。
- A1 に A2 を足す操作を A1=499 まで繰り返しながら、適宜 A3 ~ AN に A1 を足す。
- A1=500,A2=500 とする。
- A1 に A2 を足す操作を A1=500×499 まで繰り返しながら、適宜 A3 ~ AN に A1 を足す。
この手順は 2N+500×2+36×4≤201144 回以下の操作で実現可能です。
後片付け・まとめ
A1 と A2 は B と関係ない値になっているので、操作 X を用いて合わせます。
以上、平方分割→後片付けで目的を必ず達成できます (上の「簡単な場合分け」で排除した場合を除く)。
時間計算量は O(N+P) 、操作回数は 2N+2P+O(logP) です。
提出コード
提出コードのリンク:https://yukicoder.me/submissions/620527
操作回数は
- N=1 のとき高々 {(P−1)/4−1}+1=55894 回
- 2≤N のとき高々 105×2+500×2+36×8+2+1=201291 回
となり、 201291 回以下です。