AtCoder-ABC206 D - KAIBUNsyo【Python解答例】
AtCoder Beginner Contest206のD問題についてPythonの解答例を記事にしていきます。
AtCoder Beginner Contest 206(Sponsored by Panasonic) - AtCoder
AtCoder Beginner Contest206 D - KAIBUNsyo
問題文
N 項からなる正整数列 A=(A1,A2,…AN) が与えられます。
以下の操作を 0 回以上何度でも行える時、操作を最小何回行えば、A を回文にすることができますか?
ある正整数の組 (x,y) を選ぶ。その後、現在 A に含まれる x をすべて y に置き換える。
なお、この問題では、全ての整数 i (1≤i≤N) について、Ai=AN+1−i が成り立つとき、またその時に限って、A が回文であると言います。
制約
・入力は全て整数
・1≤N≤2×10^5
・1≤Ai≤2×10^5
解答例
max_num = 200010 # ノードiの親がpar[i] par = [0 for _ in range(max_num)] # 集合の要素数 size = [1 for _ in range(max_num)] # 初期化 def init(n): for i in range(max_num): # 初期化では自身を親とする par[i] = i # sizeは1 size[i]= 1 # 木の根を求める def find(x): # 自身が親なら自身の番号を返す if par[x] == x: return x else: # 根を張り替える par[x] = find(par[x]) return par[x] # xとyの属する集合を併合 def unite(x,y): root_x = find(x) root_y = find(y) # 同じグループの場合 if root_x == root_y: return # sizeの大きいほうの根に小さいほうの根をつなぐ if size[root_x] < size[root_y]: par[root_x] = root_y size[root_y] += size[root_x] else: par[root_y] = root_x size[root_x] += size[root_y] # xとyが同じ集団か def same(x,y): return find(x) == find(y) # 集団の要素数 def treesize(x): return size[find(x)] n = int(input()) A = list(map(int, input().split())) init(n) # 回文のペアを併合 for i in range(-(-n//2)): unite(A[i], A[n-1-i]) ans = 0 # 連結成分の個数-1を足し合わせる for i in range(max_num): if i == find(i): ans += treesize(i) - 1 print(ans)
解説
(詳しい説明ができませんが)正整数列Aを回文にするために何回置き換えを行えばよいか答える問題です。
回文のペアを連結していき、最後に連結成分の個数-1を足し合わせることで答えを求めました。
Union-Findはこちらでも記事にしましたが、今回は集合の要素数sizeを管理するよう変更しています。
ebisuke33.hatenablog.com
回文のペアを連結することで、仮に同じ数字の場合は要素数は変わりませんが、違う数字で置き換え操作が必要な場合はsizeが1増加します。
sizeから必要な操作回数がわかりますので、最後に各連結成分のsize-1を足し合わせれば、この値が解答となります。
ABC206の関連記事はこちら
ebisuke33.hatenablog.com
ebisuke33.hatenablog.com