バーチャル参加 ABC126
- 全完1ペナ 65分でした
A - Changing a Character
小文字に置き換えるのは python であれば s
を文字列型として s.lower()
でできます。
該当箇所のみ lower
を使って、それ以外はそのまま表示させるようにします。
N, K = map(int, input().split()) S = input() print(S[:K-1] + S[K-1].lower() + S[K:])
B - YYMM or MMYY
MM として表示できるのは になります。この範囲内であれば、MM と言えます。そうでない場合は YY です。
MMMM となる場合は AMBIGUOUS
となります。片方 MM のパターンはそのままで、それ以外は全て NA
です。
S = input() bf = S[:2]; af = S[2:] if 1 <= int(bf) <= 12: bf_flag = True else: bf_flag = False if 1 <= int(af) <= 12: af_flag = True else: af_flag = False if bf_flag and af_flag: print('AMBIGUOUS') elif bf_flag and not af_flag: print('MMYY') elif not bf_flag and af_flag: print('YYMM') else: print('NA')
C - Dice and Coin
1回目の出た目の数によって、何回あと表出し続けないといけないかが変わるのでそれごとに計算します。
1回目は から まで等確率で目が出るので、確率は 。1回目に出た値を とおくと、そのあとの確率は、表を連続して出す確率なので、 ( は を満たす最小の整数)と表せます。
これを から までのパターン全て計算して足し合わせれば良いです。
N, K = map(int, input().split()) p0 = 1/N; ans = 0.0 for score in range(1, N+1): cnt = 0 while score < K: score *= 2 cnt += 1 ans += p0 / (2 ** cnt) print(ans)
D - Even Relation
同じ色に塗られた任意の 頂点について、その距離が偶数である。
色が先で、その後距離を見ると、頂点どうしの距離が偶数である、という確認の順番です。
思いつきで、根を黒で借り決めして、距離が偶数であるときは親と同じ色、距離が奇数であるときは親と異なる色、とすると、塗り分けが可能で、問題文の状態を満たすことができます。
提出コード
from collections import deque N = int(input()) graph = [[] for _ in range(N)] for _ in range(N-1): u, v, w = map(int, input().split()) u -= 1; v -= 1 graph[u].append((v, w)) graph[v].append((u, w)) fr = 0 que = deque([fr]) goneset = set([fr]) ans = [-1] * N; ans[fr] = 0 while True: fr = que.popleft() for to, w in graph[fr]: if to in goneset: continue if w%2 == 0: ans[to] = ans[fr] else: ans[to] = (ans[fr]+1)%2 que.append(to) goneset.add(to) if len(que) == 0: break print(*ans, sep='\n')
E - 1 or 2
「 が偶数」の情報だけだと と の偶奇を確定できません。このうち片方が分かれば両方を特定できます。この場合はコスト1を使う必要があります。
また、上で明らかになった の情報が、他の で使えれば、コストを払う必要がありません。
したがって、コスト 1 払ったときに連鎖的にわかる範囲が管理できていればよく、UnionFind を使って実装できます。
提出コード
class UnionFind(): """ unionfind を扱うクラス (0-index) Parameters: ----------- n: int 管理するデータの要素数 """ def __init__(self, n:int): """ Parameters: ----------- n: int 要素数 parents: list 各要素が属する親の要素番号 grouping: set 親番号の集合 rank: list 親の rank を保持するためのリスト size: list 親の size を保持するためのリスト """ self.n = n self.parents = [-1]*n self.grouping = set(range(n)) self.rank = [0]*n self.size = [1]*n def find(self, x:int) -> int: """ 要素 x の親の要素を見つけるメソッド Parameters: ----------- x: int 要素番号 Returns: -------- int x の親の要素番号 """ if self.parents[x] < 0: return x else: self.parents[x] = self.find(self.parents[x]) return self.parents[x] def union(self, x:int, y:int) -> None: """ 要素 x, y の属するグループを結合するメソッド Parameters: ----------- x, y: int 結合対象の要素番号 """ x = self.find(x) y = self.find(y) if x == y: return if self.rank[x] < self.rank[y]: # rank(x)の方が小さい場合は, xをくっつけて, y を親にする self.size[y] += self.size[x] self.parents[x] = y self.grouping.difference_update(set([x])) else: # そうでないときは, y をくっつけて, x を親にする self.size[x] += self.size[y] self.parents[y] = x if self.rank[x] == self.rank[y]: self.rank[x] += 1 self.grouping.difference_update(set([y])) def msize(self, x:int) -> int: """ 要素 x の属するグループの大きさを返すメソッド Parameters: ----------- x: int 要素番号 Returns: -------- int x の属するグループの大きさ(要素数) """ return self.size[self.find(x)] def main(): N, M = map(int, input().split()) uf = UnionFind(N) for _ in range(M): X, Y, _ = map(int, input().split()) X -= 1; Y -= 1 uf.union(X, Y) ans = len(uf.grouping) print(ans) if __name__ == "__main__": main()
F - XOR Matching
XOR の bit 演算は、以下のようになります。
XOR | 1 | 0 |
---|---|---|
1 | 0 | 1 |
0 | 1 | 0 |
演算は、以下のように数字の各 bit どうしを比較して上記演算の結果を返します。
# ^ は XOR 5^13 #8
10進数 | 2進数 |
---|---|
5: | 0101 |
13: | 1101 |
8: | 1000 |
また、結合法則、交換則が成り立ちます。()
そして、0 は以下を満たします。
さて、問題文の状況から、 以上 未満の整数が2つずつ使える中で数列を作り、同じ値で囲まれる間の数列の XOR を行うと になるようにします。
まず、XOR は bit 演算なので、演算した後に bit の最大の桁数が増えることはありません。したがって、 の場合は XOR して を作ることができません。
そうでない場合は、数列のなかに を入れることができます。 が成り立つので、以下のように を同じ数字で囲むと、問題文の条件を満たせます。
0 2 3 4 K 4 3 2 0
どうしの場合どうするかですが、次の性質を使うと簡単です。
- から 以下の整数を全てXORすると、0 になる
よって、ここから一つ という数字を外すと、XOR は になります。
ゆえに、数列を作る際は、 どうしの間は 以外の から 以下の整数を並べれば良いです。
例えば 、 の場合は、以下のようにすれば良いです。
0 1 2 3 4 6 7 5 7 6 4 3 2 1 0 5
これで大体答えですが、特殊なケースについて考えておきます。
の場合は、隣どうし数字を並べたりすることで満たせます。
また、、 の場合は、このときは 0 と 1 しか使える数字がなく、どう並び替えても条件を満たす数列を作れません。この時は -1 を出します。
以上で、 で条件を満たす数列が作れました。
提出コード
from collections import deque M, K = map(int, input().split()) if 2**M-1 < K: print(-1) return if K == 0: ans = deque([]) for i in range(2**M): ans.appendleft(i) ans.append(i) print(*ans) return if M == 1: print(-1) return ans = deque([K]) for p in range(0, 2**M): if p != K: ans.appendleft(p) ans.append(p) ans.append(K) print(*ans)