2019年11月27日水曜日
2019年11月20日水曜日
KUPC 2014 I - Rain
合計雨量の差にしか興味がないので、費用diを使って呪文iを唱えると地域biの雨量が1減り地域aiの雨量が1増える、つまり雨量が1移動するとだけ考えればよい。雨量の移動を自由に繰り返して最小コストで雨量を平準化するのは、最小費用流問題そのものである。
最初の雨量はどの地域も0とし、呪文c1,...,cMを唱えて雨量がp1,...,pKになったとする。グラフは次のように作ればよい:
- pv>0なら、始点Sからvに容量pv、コスト0の辺を張る。
- pv<0なら、vから終点Tに容量−pv、コスト0の辺を張る。
- 各biからaiに容量∞、コストdiの辺を張る。
Sの出容量のぶんだけTに流したときの最小コストが答えであり、必要な量を流せない場合は−1である。計算量(の一例)はO(KElogV)。
2019年11月19日火曜日
JOI2011 本戦 D - 歩くサンタクロース
ひとまず一次元の問題として考える。つまり、数直線上のある地点tに降り立って、各点x1,x2,...,xnに行って帰る問題である。さらにx1≤x2≤...≤xnと仮定する。最後に訪れる点をxkとする時、総距離は
2∣t−x1∣+....+2∣t−xk−1∣+∣t−xk∣+2∣t−xk+1∣+...+2∣t−xn∣となる。絶対値関数の和は下に凸になり、区分する点の中央値で最小値を取ることを使えそうな気がする。しかし、係数が邪魔なので開いて並べる:
∣t−x1∣,∣t−x1∣,...,∣t−xk−1∣,∣t−xk∣,∣t−xk+1∣,...,∣t−xn∣,∣t−xn∣これら2n−1個の点の真ん中にある点xlは(奇数個だから)一点に定まるので、上の式にt=xlを代入すると最小値が求まる。具体的には、右側にあるn−1個のxiを足して左側にあるn−1個のxiを引けばよい。最後に訪れる点をn通り試せば答えがわかる。二次元の場合もまったく同じで、x方向とy方向について独立に求めてから和を取ればよい。
実装について。いろいろやり方はありそうだけど、ソートされた列に順序を保って挿入・削除する操作があって、さらに区間の和が高速に求まれば直接的にシミュレーションできるのでそれがもっとも簡単に見える。平衡二分木ならどちらもO(logN)でできる。
けっきょく真ん中になりえる点は1個か2個しかないので、それを試すだけでよいらしい。途中で気づきたかった。
2019年11月13日水曜日
JAG Summer Camp 2013 Day 2 G - Perm Query
与えられた置換pを巡回置換の合成σ1σ2...σkに分解して、ある巡回置換σに注目する。σの長さがdとすると、
- 列σxの区間[l,r]の総和
- 列σ2xの区間[l,r]の総和
- ...
- 列σdx=xの区間[l,r]の総和
をすべて足せばこの巡回置換を一周した場合の総和が求まることになる。この際、巡回置換に現れるすべての数は同じ回数だけ[l,r]に現れるので、上の総和は巡回置換に登場する数の総和の倍数になっている。
また、問題のようにすべての巡回置換を同時に適用した場合、次にもとに戻るのは(区間[l,r]に登場する)すべての巡回置換の長さの最小公倍数である。これをLCM(l,r)とすると、LCM(l,r)回の操作を行う場合、長さdの巡回置換についてはLCM(l,r)/d周することになる。この際、巡回置換に登場する数で最初に区間[l,r]に含まれていたものがq個であるとすると、巡回置換に登場する数はそれぞれqLCM(l,r)/d回足されることになる。
実装で迷った末に、Moのアルゴリズムを使った。
区間[l,r]についての値がわかっているとき、[l,r+1]の値を考える。まず、区間が伸びたことによって操作回数がLCM(l,r)からLCM(l,r+1)に伸びるので、既存の値がLCM(l,r+1)/LCM(l,r)倍になる。また、位置r+1が追加されるので、この位置を含む巡回置換σの長さdについて、(巡回置換σに登場する数の総和)×LCM(l,r+1)/dが加算されることになり、新しい値が求まる。区間が縮む場合も同様に書ける。
LCM(l,r)の値を得るのにsparse tableが使えるから計算量の問題はないと思って書き出したのだが、伸縮の際にmodの割り算が必要になるので結局logがついてO(NQlogN)だった。[1]
lcmと同時に、それぞれの巡回置換の総和もセグメント木で持てばよいらしい。それはそうか……
lcmの範囲が大きいので逆数のテーブルは用意できない。でも、うまい方法がありそうな気もする。 ↩︎
2019年11月10日日曜日
2019年11月8日金曜日
2019年11月5日火曜日
ARC 044 B - 最短路問題
とりあえずソートしてランレングス圧縮して、同じ距離の頂点グループ毎にグラフを作っていくことを考える。距離0は頂点1だけとか、距離が飛んでいる部分があってはいけないとか、そういうケースは最初に考慮しておく。
頂点1からの距離がiの頂点がBi個あるとする。距離iの頂点同士はどうつないでもほかの頂点と1との距離に影響しない。したがって、(2Bi)通りのペアすべてに自由に辺を張れるので、距離iに対して2(2Bi)通りの辺の張り方があることになる。
次に、距離i−1の頂点グループと距離iの頂点グループをつなぐ辺の張り方を考える。これもだいたい自由に辺を張れるのだが、距離iの頂点は、距離i−1のBi−1個の頂点のうち少なくとも1つにはつながれていなければならないという制約がある。「少なくとも1つ」は包除原理で書ける:
==2Bi−1Bi−(1Bi)2Bi−1(Bi−1)+(2Bi)2Bi−1(Bi−2)−...+(−1)Bi(BiBi)2Bi−1⋅0k=0∑Bi(kBi)(−1)k(2Bi−1)Bi−k(2Bi−1−1)Bi
あっ……
包除で求めてから自明な数え方に気づくパターン、これで3回目くらい。