ABC022は開始時刻に間に合わず不参加。
http://abc022.contest.atcoder.jp/assignments
A - Best Body
N日間の体重遷移の情報として、初日の体重Wと、2日目以降における前日との体重差分A[i]が与えられる。
適正体重であるS~Tの間に入る日を求めよ。
W+=A[i]で体重を更新し、S~Tに収まるか判定すればよい。
Python はS ≦ W ≦ Tという表記ができて良いね。
N,S,T=map(int,raw_input().strip().split(" ")) ret=0 W=0 for i in range(N): W+=input() if S<= W <=T: ret += 1 print ret
B - Bumble Bee
ハチがN個の花を順に訪れる。
i番目に訪れる花の種類はA[i]である。
その際、以前に同じ花を訪れていた場合、i番目の花に受粉する。
全体で受粉する花の数を求めよ。
setなり、花の種類ごとのカウンタなりで、各花が訪問済みか管理すればよい。
N=input() ret=0 hist=[0]*101000 for i in range(N): x=input() if hist[x] > 0: ret += 1 hist[x] = 1 print ret
C - Blue Bird
N頂点M距離付無向辺の無向グラフが与えられる。
1番の頂点から始まり、他の頂点を1個以上通り、同じ辺を2回以上通らないようにして元の頂点に戻る経路のうち、最短経路の距離を求めよ。
自分は以下の3通りで通した。上2つはPythonではTLEするので注意。
- 1番とx番の辺を取り除いた状態で1番からx番への最短経路を求め、元の1番とx番の辺を追加すれば条件を満たす移動経路が求められる。そこでx番を総当たりして最小値を求めればよい。
- (N-1)回Dijkstraを行うので、O(N^3*logN)かかる。
- 2番~N番の頂点でWarshall-Floyed法で全点間最短経路を求める。次に2番~N番の頂点から2個x,yを総当たりし、1→x→y→1とたどる経路の最小値を求めればよい。
- 後半の総当たりパートはO(N^2)だが、WF法パートでO(N^3)かかる。
- Editorialの最後にあった最短経路木を用いる方法。
- まずDijkstra法を用いて最短経路を求める。その際、1番に隣接するどの頂点を経由したかによって頂点をグループ分けする。
- 最短経路に含まれない辺を用いると異なるグループを結べるのであれば、条件を示す経路を作れる。
- よって最短経路に含まれない辺を総当たりし、経路長の最小値を求めればよい。
- DijkstraパートでO(N^2*logN)、辺の総当たりパートでO(N^2)なので、こちらはPythonで間に合う。
import sys import math import Queue N,M=map(int,raw_input().strip().split(" ")) mat=[[1<<60 for i in range(301)] for j in range(301)] group=[0]*301 for i in range(M): x,y,l=map(int,raw_input().strip().split(" ")) mat[x-1][y-1]=mat[y-1][x-1]=l dist = [1<<60] * N dist[0]=0 Q = Queue.PriorityQueue() Q.put((0,0)) while Q.qsize() > 0: ent = Q.get() co = ent[0] cur = ent[1] if dist[cur] != co: continue for i in range(N): if mat[cur][i]>=0 and co + mat[cur][i] < dist[i]: if cur==0: group[i]=i else: group[i]=group[cur] dist[i] = co + mat[cur][i] Q.put((dist[i],i)) mi=1<<60 for x in range(1,N): if group[x] != x: mi = min(mi, dist[x]+mat[0][x]) for y in range(x+1,N): if group[x] != group[y]: mi = min(mi, dist[x] + mat[x][y] + dist[y]) if mi >= 1<<60: mi = -1 print mi
D - Big Bang
2次元上でN個の頂点群の座標A[i]が与えられる。
これらを同じ距離・同じ向きに平行移動し、同じ角度原点を中心に回転移動し、原点を中心にP倍拡大したところ、各頂点の座標はB[i]となった。
Pを求めよ。
Pさえ求められればいいので、図形全体に対しPだけ差が出るようなパラメータに注目し、移動前後のパラメータの変化を求める。
自分は以下の2通りでやった。前者はC++だと通るが、Pythonだと通らない。
- A,Bの凸包を求め、辺の総長や最短辺長の比を求める。この比はPである。
- 凸包パートでO(N*logN)かかる。
- A,Bそれぞれ重心が原点に来るよう平行移動し、原点から全頂点への距離の総和を求める。この比もPである。
- こちらはO(N)なのでPythonでも間に合う。
import math def dsum(P): tx=ty=0 for x,y in P: tx += 1.0*x ty += 1.0*y tx /= len(P) ty /= len(P) tl = 0 for x,y in P: x -= tx y -= ty tl += (x*x+y*y) ** 0.5 return tl N=input() TL=[] for i in range(2): P = [] for j in range(N): P.append(map(int,raw_input().strip().split(" "))) TL.append(dsum(P)) print TL[1]/TL[0]
まとめ
CもDもPythonだと大変だと思ったけど、良く考えたらDは簡単だったな。
無駄に凸包ライブラリをPythonに移植しちゃったよ。