Skip to content

Commit 47ebc2c

Browse files
authored
Merge pull request #197 from OUCC/blog/ABC436
記事作成
2 parents 21add31 + aeee4c9 commit 47ebc2c

File tree

2 files changed

+191
-0
lines changed

2 files changed

+191
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"postDate": "2025-12-13T14:47:49.960Z"
3+
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
---
2+
title: ABC436感想記事
3+
description: ABC436の感想を書く。
4+
author: yuuma
5+
category: other
6+
tags: [advent-calendar,kyopuro]
7+
---
8+
- この記事は [OUCC Advent Calendar 2025](https://adventar.org/calendars/12077) の14日目の記事です。
9+
- ABC436に参加した感想を書きます。(~~ネタがない(2回目)~~)
10+
## AtCoderとは
11+
- AtCoderはざっくりいうとプログラミングの問題を解くコンテストを開催しているサイトです。ABCはAtCoder Beginner Contestの略で、初心者向け?のコンテストです。大体毎週土曜日の21:00から開催され、制限時間は100分です。
12+
- リンク: https://atcoder.jp/
13+
## 全体の感想
14+
- 今日はE問題まで解けたのでそこまで解説しますが、Eが完全エスパーなので解説とは?になります。
15+
## A問題
16+
- 問題文: https://atcoder.jp/contests/abc436/tasks/abc436_a
17+
- 解法: oを先頭にN-len(S)個追加してからSを追加すれば構築可能です。
18+
- 提出コード
19+
```python
20+
N=int(input())
21+
S=input()
22+
ans=[]
23+
for i in range(N-len(S)):
24+
ans.append("o")
25+
for i in range(len(S)):
26+
ans.append(S[i])
27+
print("".join(ans))
28+
```
29+
## B問題
30+
- 問題文: https://atcoder.jp/contests/abc436/tasks/abc436_b
31+
- 解法: 本当に問題文通りに実装をします。頭がバグらないようにni,njは入れるもの、i,jは以前の位置を保持するようにしました。
32+
- 提出コード
33+
```python
34+
N=int(input())
35+
G=[[0]*N for _ in range(N)]
36+
f=0
37+
i=0
38+
j=(N-1)//2
39+
G[i][j]=f+1
40+
f+=1
41+
while f<N*N:
42+
ni=(i-1)%N
43+
nj=(j+1)%N
44+
if G[ni][nj]!=0:
45+
ni=(i+1)%N
46+
nj=j
47+
G[ni][nj]=f+1
48+
f+=1
49+
i=ni
50+
j=nj
51+
for ans in G:
52+
print(*ans)
53+
54+
```
55+
## C問題
56+
- 問題文: https://atcoder.jp/contests/abc436/tasks/abc436_c
57+
- 解法: 2×2の正方形が重なるいうことは4つのマスのいずれかが既に使われていると考えればsetを使えばできそうです。
58+
- 提出コード
59+
```python
60+
N,M=map(int,input().split())
61+
S=set()
62+
ans=0
63+
L=[(0,0),(0,1),(1,0),(1,1)]
64+
for i in range(M):
65+
a,b=map(int,input().split())
66+
f=True
67+
for di,dj in L:
68+
na=di+a
69+
nb=dj+b
70+
if (na,nb) in S:
71+
f=False
72+
if f:
73+
for di,dj in L:
74+
na=di+a
75+
nb=dj+b
76+
S.add((na,nb))
77+
ans+=1
78+
print(ans)
79+
```
80+
## D問題
81+
- 問題文: https://atcoder.jp/contests/abc436/tasks/abc436_d
82+
- 解法: 前回でも使いましたBFSです。ワープの場合がだるかったんですが、生ける先を管理してa,bからの移動先として実装しました。一度ワープを使ったらもう一度そこに行く場合は必ず手数が増えるので考えないようにします。ワープ用のdist更新を行わない場所(超頂点)を作ってもよかったかも。
83+
- 提出コード
84+
```python
85+
L=[(1,0),(-1,0),(0,1),(0,-1)]
86+
H,W=map(int,input().split())
87+
E=[[] for i in range(26)]
88+
G=[list(input()) for _ in range(H)]
89+
dist=[[-1]*W for _ in range(H)]
90+
visited=[False]*26
91+
dist[0][0]=0
92+
for i in range(H):
93+
for j in range(W):
94+
if G[i][j]!="." and G[i][j]!="#":
95+
E[ord(G[i][j])-ord("a")].append((i,j))
96+
from collections import deque
97+
q=deque()
98+
q.append((0,0))
99+
while q:
100+
a,b=q.popleft()
101+
for di,dj in L:
102+
na=a+di
103+
nb=b+dj
104+
if 0<=na<H and 0<=nb<W:
105+
if dist[na][nb]!=-1:
106+
continue
107+
108+
if G[na][nb]=="#":
109+
continue
110+
else:
111+
q.append((na,nb))
112+
dist[na][nb]=dist[a][b]+1
113+
if G[a][b]!="." and G[a][b]!="#":
114+
if visited[ord(G[a][b])-ord("a")]==True:
115+
continue
116+
else:
117+
visited[ord(G[a][b])-ord("a")]=True
118+
for na,nb in E[ord(G[a][b])-ord("a")]:
119+
if dist[na][nb]!=-1:
120+
continue
121+
q.append((na,nb))
122+
dist[na][nb]=dist[a][b]+1
123+
print(dist[-1][-1])
124+
```
125+
## E問題
126+
- 問題文: https://atcoder.jp/contests/abc436/tasks/abc436_e
127+
- 解法: 入れ替えをすることでソートが行われるものを考えます。例えば2 1 4 3という並びがあると1と3,4と入れ替えても意味はありません。よってこれは(2,1)と(4,3)のグループに分けて考えることができます。このグループ分けはUnion-Findで実装可能です。各個数においては、よくわかりませんが実験の結果1個なら0通り、2個なら1通り、3個なら3通り、4個なら6通りだったので、n*(n-1)/2通りになると予想しました。(通ったので正しいはず)
128+
- 提出コード
129+
```python
130+
N=int(input())
131+
A=list(map(int,input().split()))
132+
133+
class UnionFind():
134+
# 初期化
135+
def __init__(self, n):
136+
self.par = [-1] * n
137+
self.rank = [0] * n
138+
self.siz = [1] * n
139+
140+
# 根を求める
141+
def root(self, x):
142+
if self.par[x] == -1: return x # x が根の場合は x を返す
143+
else:
144+
self.par[x] = self.root(self.par[x]) # 経路圧縮
145+
return self.par[x]
146+
147+
# x と y が同じグループに属するか (根が一致するか)
148+
def issame(self, x, y):
149+
return self.root(x) == self.root(y)
150+
151+
# x を含むグループと y を含むグループを併合する
152+
def unite(self, x, y):
153+
# x 側と y 側の根を取得する
154+
rx = self.root(x)
155+
ry = self.root(y)
156+
if rx == ry: return False # すでに同じグループのときは何もしない
157+
# union by rank
158+
if self.rank[rx] < self.rank[ry]: # ry 側の rank が小さくなるようにする
159+
rx, ry = ry, rx
160+
self.par[ry] = rx # ry を rx の子とする
161+
if self.rank[rx] == self.rank[ry]: # rx 側の rank を調整する
162+
self.rank[rx] += 1
163+
self.siz[rx] += self.siz[ry] # rx 側の siz を調整する
164+
return True
165+
166+
# x を含む根付き木のサイズを求める
167+
def size(self, x):
168+
return self.siz[self.root(x)]
169+
uf=UnionFind(N+1)
170+
for i in range(N):
171+
uf.unite(i+1,A[i])
172+
ans=0
173+
S=set()
174+
for i in range(N):
175+
a=uf.root(i+1)
176+
if a not in S:
177+
b=uf.size(a)
178+
ans+=b*(b-1)//2
179+
S.add(a)
180+
print(ans)
181+
```
182+
こっからは解けなかったんですが、問題文だけ乗せときます。
183+
## F問題
184+
- 問題文: https://atcoder.jp/contests/abc436/tasks/abc436_f
185+
## G問題
186+
- 問題文: https://atcoder.jp/contests/abc436/tasks/abc436_g
187+
## 最後に
188+
以上でabc436の感想を終わります。ここ2回分の感想を書いてるのですが重要なアルゴリズムやデータ構造がたくさん出てきているので書いていて楽しいです。あとは次で2分探索、累積和、動的計画法のどれかが出てくれると嬉しい。さてこれで感想記事を終わります。AtCoderに興味を持ったら一度参加してみましょう!!!来週もおそらく感想記事を書くので、そちらもよろしくお願いします。

0 commit comments

Comments
 (0)