2019年4月29日月曜日
2019年4月27日土曜日
ABC 125 C - GCD on Blackboard
危うく平方分割するところだった……
Aiを書き換えるとき、最大公約数は高々gcd(A1,...,Ai−1,Ai+1,...,AN)であり、実際、Aiをgcd(A1,...,Ai−1,Ai+1,...,AN)に書き換えればこの値にできる。したがって、G(i):=gcd(A1,...,Ai−1,Ai+1,...,AN)とすると、G(i)の最大値が答えである。
L(i):=gcd(A1,...,Ai−1), R(i)=gcd(Ai+1,...,AN)とするとG(i)は
G(i)=gcd(L(i),R(i))
で計算できるので、
L(i):=gcd(L(i−1),Ai−1)R(i):=gcd(R(i+1),Ai+1)
を利用して先にL(i), R(i)のテーブルを作っておけばよい。
あと、今まで意識したことがなかったけど、gcd
の単位元として0が使えるという理解を得た。
別解とか
今回のCってこれだけだと思うんですけど pic.twitter.com/JKK0zBK1bf
— じゅぴちゃん (@jupiro_jupi) April 27, 2019
これはうまい考え方だと思った。……けど、最初の2つの数の約数から素朴に調べる方針だと、例えば
100000
735134400 698377680 735134400 ... (99996個連続) ... 735134400 1 1
みたいな入力でけっこう時間が怪しい。とはいっても、高々2×108程度のループですむので、C++なら大丈夫だろうな。1
Divisor function d(n)の上限を見る限り、計算量は任意のϵ>0に対してo(N(maxAi)ϵ)と評価できるようだが、漸近的な評価があまり役に立たない例にも見える。supi≤nd(i)の具体的な値を覚えておいたほうが良さそう。
参考: https://gist.github.com/dario2994/fb4713f252ca86c1254d
2019年4月26日金曜日
ABC 018 C - 菱形カウント
長方形領域の周りがx
で囲われているものとして考える:
xxxxxxx
xxoooox
xooooxx
xooooox
xoxxoox
xxxxxxx
x
からの最短距離がK以上であるマスがわかれば、その数が答えである。具体的には、マスx
を0に、マスo
をinfに初期化した上で、0に初期化した点をすべてキューに入れてBFSすれば良い:
0 0 0 0 0 0 0
0 0 inf inf inf inf 0
0 inf inf inf inf 0 0
0 inf inf inf inf inf 0
0 inf 0 0 inf inf 0
0 0 0 0 0 0 0
↓
0 0 0 0 0 0 0
0 0 1 1 1 1 0
0 1 2 2 1 0 0
0 1 1 1 2 1 0
0 1 0 0 1 1 0
0 0 0 0 0 0 0
計算量はO(RC)。
2019年4月25日木曜日
ABC 011 D - 大ジャンプ
以下、X,Yは最初からDで割ったものを扱い、D=1とする。x軸に沿ってk+回+1進み、k−回−1進み、y軸に沿ってl+回+1進み、l−回−1進む場合を考える。このように進む確率をP(k+,k−,l+,l−)とすると、
P(k+,k−,l+,l−)=(k+N)(k−N−k+)(l+N−k+−k−)4−N
である。あとは(X,Y)にたどりつくようなk+,k−,l+,l−の組み合わせについてPを足し合わせればよい。具体的には、k+が与えられたとき、k+−k−=X, l+−l−=Y, k++k−+l++l−=Nより、残りは以下のように定まる。
k−l+l−===k+−X21(N−k+−k−+Y)21(N−k+−k−−Y)
したがって、各k+∈{0,1,...,N}について(k−, l+, l−が有効な値なら)P(k+,k−,l+,l−)を足し合わせると、それが答えになる。
しかし、上のPをそのまま計算すると倍精度ではオーバーフローしてしまうので、logを経由することにする:
P(k+,k−,l+,l−)=exp(log(k+N)+log(k−N−k+)+log(l+N−k+−k−)−Nlog4)
log(mn)=logn!−logm!−log(n−m)!だから、階乗の対数が求まればよい。今回はNが小さいので素朴に足す1だけでも問題ないし、大きい場合も精度のよい漸近公式がいろいろある。2
想定解法ではなさそうと思いながら書いた。対数を取る方法は、ABC 094 - Dがわからなくて苦し紛れに書いたのをコピペしただけなのだが、(精度的な意味で)どのくらい頑健なのかよくわかっていない。
想定解法は、最初から確率で遷移することで、値が大きくならないようにするというものだった。パスカルの三角形の(mn)/2nバージョンは頭に入れておいたほうが良さそう。