2020年2月3日月曜日

JOI2007 春合宿 - circuit

置換の累乗根を考える問題。ひとまず置換を巡回置換に分解すると、巡回置換の長さと個数だけに意味があることがわかる。与えられた置換が長さllの巡回置換C(l)C(l)個から構成されるとして、累乗根を探す。

一般に長さLLの巡回置換をkk乗すると長さL/gcd(L,k)L/\gcd(L, k)の巡回置換gcd(L,k)\gcd(L, k)個に分解される。逆に長さllの巡回置換がいくつかある時、L=gcd(L,k)lL = \gcd(L, k)lを満たすようなLLがあれば、長さllの巡回置換をgcd(L,k)\gcd(L, k)個合わせた置換のkk乗根として長さLLの巡回置換を構成できる。

そこで、長さllの巡回置換に対して可能な長さLLの集合をS(l,k)S(l, k)とする:

S(l,k)={L:L=lgcd(L,k),Lf(l)l} S(l, k) = \{L : L = l\gcd(L, k), \: L \le f(l)l\}

長さLS(l,k)L \in S(l, k)を採用するとき、長さllの巡回置換をgcd(L,k)\gcd(L, k)個消費して(kk乗根となる長さLLの)巡回置換が作れることになる。したがって、この問題はS(l,k)S(l, k)内の長さを重複を許して自由に使ってC(l)C(l)個をちょうど消費する問題になる。(重複あり部分和問題) この問題をすべてのllについて解けばよい。解けないllがあれば解なしとなる。

計算量について。S(l,k)S(l, k)を求めるのは1,2,...f(l)l1, 2, ...f(l)lをすべて試せばよくて、f(l)lf(l)lの総和はちょうどNNに等しいのでこの部分はO(N){O}(N)である。LLkkの約数にllを掛けたものだから、S(l,k)S(l, k)のサイズはkkの約数の総数d(k)d(k)を超えない。したがって、各部分和問題のサイズはC(l)d(k)C(l)d(k)で総和はNd(k)Nd(k)。全体の計算量もO(Nd(k)){O}(Nd(k))になる。