Open34
蟻本

P8 くじびき
N, M = map(int, input().split())
K = list(map(int, input().split()))
S = set(i + j for i in K for j in K)
f = any(M - s in S for s in S)
print("Yes" if f else "No")

P21 三角形
N = int(input())
A = list(map(int, input().split()))
A.sort()
ans = 0
for i in range(N - 2):
if A[i] + A[i + 1] > A[i + 2]:
ans = max(ans, sum(A[i : i + 3]))
print(ans)

P23 Ants (POJ No.1852)
N, L = map(int, input().split())
X = list(map(int, input().split()))
t_min = max(min(x, L - x) for x in X)
t_max = max(max(x, L - x) for x in X)
print(t_min, t_max)

P34 部分和問題
N, K = map(int, input().split())
A = list(map(int, input().split()))
f = False
for bit in range(1 << N):
sum = 0
for i in range(N):
if bit & 1 << i:
sum += A[i]
if sum == K:
f = True
print("Yes" if f else "No")

P35 Lake Counting
import sys
sys.setrecursionlimit(10 ** 6)
def dfs(x, y):
G[x][y] = "."
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
nx, ny = x + dx, y + dy
if G[nx][ny] == "W":
dfs(nx, ny)
N, M = map(int, input().split())
G = [list(input()) for _ in range(N)]
for g in G:
g.append(".")
G.append(["."] * (M + 1))
ans = 0
for i in range(N):
for j in range(M):
if G[i][j] == "W":
dfs(i, j)
ans += 1
print(ans)

P37 迷路の最短路
from collections import deque
N, M = map(int, input().split())
G = [list(input()) for _ in range(N)]
for g in G:
g.append("#")
G.append(["#"] * (M + 1))
INF = 1 << 60
d = [[INF] * M for _ in range(N)]
q = deque()
for i in range(N):
for j in range(M):
if G[i][j] == "S":
d[i][j] = 0
q.append((i, j))
while q:
x, y = q.popleft()
if G[x][y] == "G":
print(d[x][y])
break
for dx, dy in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
nx, ny = x + dx, y + dy
if G[nx][ny] != "#" and d[nx][ny] == INF:
d[nx][ny] = d[x][y] + 1
q.append((nx, ny))

P42 硬貨の問題
A = int(input())
C = list(map(int, input().split()))
V = [1, 5, 10, 50, 100, 500]
ans = 0
for i in reversed(range(6)):
t = min(A // V[i], C[i])
A -= t * V[i]
ans += t
print(ans)

P43 区間スケジューリング問題
N = int(input())
ST = [tuple(map(int, input().split())) for _ in range(N)]
ST.sort(key=lambda x: x[1])
last = 0
ans = 0
for s, t in ST:
if last < s:
last = t
ans += 1
print(ans)

P45 Best Cow Line (POJ 3617)
N = int(input())
S = input()
l = 0
r = N - 1
ans = ""
while l <= r:
if S[l : r + 1] < S[l : r + 1][::-1]:
ans += S[l]
l += 1
else:
ans += S[r]
r -= 1
print(ans)

P47 Saruman's Army (POJ 3069)
from bisect import bisect_right
N, R = map(int, input().split())
X = list(map(int, input().split()))
X.sort()
i = 0
ans = 0
while i < N:
i = bisect_right(X, X[i] + R) - 1
ans += 1
i = bisect_right(X, X[i] + R)
print(ans)

P49 Fence Repair (POJ 3253)
import heapq
N = int(input())
L = list(map(int, input().split()))
heapq.heapify(L)
ans = 0
while len(L) >= 2:
l1 = heapq.heappop(L)
l2 = heapq.heappop(L)
ans += l1 + l2
heapq.heappush(L, l1 + l2)
print(ans)

P52 01 ナップサック問題
import numpy as np
N, W = map(int, input().split())
WV = [tuple(map(int, input().split())) for _ in range(N)]
dp = np.zeros(W + 1, np.int64)
for w, v in WV:
dp[w:] = np.maximum(dp[w:], dp[:-w] + v)
print(dp[W])

P56 最長共通部分列問題
import numpy as np
N, M = map(int, input().split())
S = np.array(list(input()))
T = np.array(list(input()))
equal = S[:, None] == T[None, :]
dp = np.zeros(M + 1, np.int64)
for i in range(N):
dp[1:] = np.maximum(dp[1:], dp[:-1] + equal[i])
dp = np.maximum.accumulate(dp)
print(dp[M])

P58 個数制限なしナップサック問題
N, W = map(int, input().split())
WV = [tuple(map(int, input().split())) for _ in range(N)]
dp = [0] * (W + 1)
for w, v in WV:
for i in range(w, W + 1):
dp[i] = max(dp[i], dp[i - w] + v)
print(dp[W])

P60 01 ナップサック問題その2
import numpy as np
N, W = map(int, input().split())
WV = [tuple(map(int, input().split())) for _ in range(N)]
MAX_V = 100
INF = 1 << 60
dp = np.full(MAX_V * N + 1, INF, np.int64)
dp[0] = 0
for w, v in WV:
dp[v:] = np.minimum(dp[v:], dp[:-v] + w)
ans = np.where(dp <= W)[0][-1]
print(ans)

P62 個数制限付き部分和問題
import numpy as np
N, K = map(int, input().split())
AM = [tuple(map(int, input().split())) for _ in range(N)]
dp = np.full(K + 1, -1, np.int64)
dp[0] = 0
for a, m in AM:
dp = np.where(dp >= 0, m, -1)
for i in range(a, K + 1):
dp[i] = max(dp[i], dp[i - a] - 1)
print("Yes" if dp[K] >= 0 else "No")

P63 最長増加部分列問題
from bisect import bisect_left
N = int(input())
A = list(map(int, input().split()))
INF = 1 << 60
dp = [INF] * N
for a in A:
dp[bisect_left(dp, a)] = a
ans = bisect_left(dp, INF)
print(ans)

P66 分割数
N, M, MOD = map(int, input().split())
dp = [0] * (N + 1)
dp[0] = 1
for i in range(1, M + 1):
for j in range(i, N + 1):
dp[j] = (dp[j] + dp[j - i]) % MOD
print(dp[N])

P67 重複組み合わせ
import numpy as np
N, M, MOD = map(int, input().split())
A = list(map(int, input().split()))
dp = np.zeros(M + 1, np.int64)
dp[0] = 1
for a in A:
dp[a + 1 :] -= dp[: -(a + 1)]
dp = np.cumsum(dp) % MOD
print(dp[M])

P73 Expedition (POJ 2431)
import heapq
N, L, P = map(int, input().split())
AB = [tuple(map(int, input().split())) for _ in range(N)]
AB.append((L, 0))
que = []
pos = 0
ans = 0
for a, b in AB:
P -= a - pos
while P < 0:
if not que:
print(-1)
exit()
P += -heapq.heappop(que)
ans += 1
heapq.heappush(que, -b)
pos = a
print(ans)

P85 食物連鎖 (POJ 1182)
DSU
import sys
sys.setrecursionlimit(10 ** 6)
class DSU:
def __init__(self, n):
self._n = n
self.parent_or_size = [-1] * n
def merge(self, a, b):
assert 0 <= a < self._n
assert 0 <= b < self._n
x, y = self.leader(a), self.leader(b)
if x == y:
return x
if -self.parent_or_size[x] < -self.parent_or_size[y]:
x, y = y, x
self.parent_or_size[x] += self.parent_or_size[y]
self.parent_or_size[y] = x
return x
def same(self, a, b):
assert 0 <= a < self._n
assert 0 <= b < self._n
return self.leader(a) == self.leader(b)
def leader(self, a):
assert 0 <= a < self._n
if self.parent_or_size[a] < 0:
return a
self.parent_or_size[a] = self.leader(self.parent_or_size[a])
return self.parent_or_size[a]
def size(self, a):
assert 0 <= a < self._n
return -self.parent_or_size[self.leader(a)]
def groups(self):
leader_buf = [self.leader(i) for i in range(self._n)]
result = [[] for _ in range(self._n)]
for i in range(self._n):
result[leader_buf[i]].append(i)
return [r for r in result if r != []]
# ここにDSUのコードを貼り付ける
N, K = map(int, input().split())
TXY = [tuple(map(int, input().split())) for _ in range(K)]
dsu = DSU(N * 3 + 1)
ans = 0
for (t, x, y) in TXY:
if not (1 <= x <= N and 1 <= y <= N):
ans += 1
continue
if t == 1:
if dsu.same(x, y + N) or dsu.same(x, y + N * 2):
ans += 1
else:
dsu.merge(x, y)
dsu.merge(x + N, y + N)
dsu.merge(x + N * 2, y + N * 2)
else:
if dsu.same(x, y) or dsu.same(x, y + N * 2):
ans += 1
else:
dsu.merge(x, y + N)
dsu.merge(x + N, y + N * 2)
dsu.merge(x + N * 2, y)
print(ans)

P93 二部グラフ判定
DSU
import sys
sys.setrecursionlimit(10 ** 6)
class DSU:
def __init__(self, n):
self._n = n
self.parent_or_size = [-1] * n
def merge(self, a, b):
assert 0 <= a < self._n
assert 0 <= b < self._n
x, y = self.leader(a), self.leader(b)
if x == y:
return x
if -self.parent_or_size[x] < -self.parent_or_size[y]:
x, y = y, x
self.parent_or_size[x] += self.parent_or_size[y]
self.parent_or_size[y] = x
return x
def same(self, a, b):
assert 0 <= a < self._n
assert 0 <= b < self._n
return self.leader(a) == self.leader(b)
def leader(self, a):
assert 0 <= a < self._n
if self.parent_or_size[a] < 0:
return a
self.parent_or_size[a] = self.leader(self.parent_or_size[a])
return self.parent_or_size[a]
def size(self, a):
assert 0 <= a < self._n
return -self.parent_or_size[self.leader(a)]
def groups(self):
leader_buf = [self.leader(i) for i in range(self._n)]
result = [[] for _ in range(self._n)]
for i in range(self._n):
result[leader_buf[i]].append(i)
return [r for r in result if r != []]
# ここにDSUのコードを貼り付ける
N, M = map(int, input().split())
AB = [tuple(map(int, input().split())) for _ in range(M)]
dsu = DSU(N * 2)
for a, b in AB:
if dsu.same(a, b) or dsu.same(a + N, b + N):
print("No")
exit()
dsu.merge(a, b + N)
dsu.merge(a + N, b)
print("Yes")

P102 Roadblocks (POJ No.3255)
import heapq
N, R = map(int, input().split())
ABC = [tuple(map(int, input().split())) for _ in range(R)]
G = [[] for _ in range(N)]
for a, b, cost in ABC:
a -= 1
b -= 1
G[a].append((b, cost))
G[b].append((a, cost))
INF = 1 << 60
d1 = [INF] * N
d2 = [INF] * N
d1[0] = 0
que = [(0, 0)]
while que:
d, v = heapq.heappop(que)
if d > d2[v]:
continue
for to, cost in G[v]:
if d + cost < d1[to]:
d1[to] = d + cost
heapq.heappush(que, (d1[to], to))
if d1[to] < d + cost < d2[to]:
d2[to] = d + cost
heapq.heappush(que, (d2[to], to))
print(d2[N - 1])

P103 Conscription (POJ No.3723)
DSU
import sys
sys.setrecursionlimit(10 ** 6)
class DSU:
def __init__(self, n):
self._n = n
self.parent_or_size = [-1] * n
def merge(self, a, b):
assert 0 <= a < self._n
assert 0 <= b < self._n
x, y = self.leader(a), self.leader(b)
if x == y:
return x
if -self.parent_or_size[x] < -self.parent_or_size[y]:
x, y = y, x
self.parent_or_size[x] += self.parent_or_size[y]
self.parent_or_size[y] = x
return x
def same(self, a, b):
assert 0 <= a < self._n
assert 0 <= b < self._n
return self.leader(a) == self.leader(b)
def leader(self, a):
assert 0 <= a < self._n
if self.parent_or_size[a] < 0:
return a
self.parent_or_size[a] = self.leader(self.parent_or_size[a])
return self.parent_or_size[a]
def size(self, a):
assert 0 <= a < self._n
return -self.parent_or_size[self.leader(a)]
def groups(self):
leader_buf = [self.leader(i) for i in range(self._n)]
result = [[] for _ in range(self._n)]
for i in range(self._n):
result[leader_buf[i]].append(i)
return [r for r in result if r != []]
# ここにDSUのコードを貼り付ける
N, M, R = map(int, input().split())
XYD = [tuple(map(int, input().split())) for _ in range(R)]
XYD.sort(key=lambda x: -x[2])
dsu = DSU(N + M)
ans = 10000 * (N + M)
for x, y, d in XYD:
if not dsu.same(x, y + N):
dsu.merge(x, y + N)
ans -= d
print(ans)

P104 Layout (POJ No.3169)
N, ML, MD = map(int, input().split())
ABD_L = [tuple(map(int, input().split())) for _ in range(ML)]
ABD_D = [tuple(map(int, input().split())) for _ in range(MD)]
edges = []
for i in range(N - 1):
edges.append((i + 1, i, 0))
for al, bl, dl in ABD_L:
al -= 1
bl -= 1
edges.append((al, bl, dl))
for ad, bd, dd in ABD_D:
ad -= 1
bd -= 1
edges.append((bd, ad, -dd))
INF = 1 << 60
dist = [INF] * N
dist[0] = 0
updated = False
for i in range(N):
for v, u, cost in edges:
if dist[v] != INF and dist[u] > dist[v] + cost:
dist[u] = dist[v] + cost
if i == N - 1:
updated = True
if updated:
print(-1)
elif dist[N - 1] == INF:
print(-2)
else:
print(dist[N - 1])

P107 線分上の格子点の個数
from math import gcd
P1 = tuple(map(int, input().split()))
P2 = tuple(map(int, input().split()))
ans = gcd(P1[0] - P2[0], P1[1] - P2[1]) - 1
print(ans)

P108 双六
def extgcd(a, b):
if not b:
return a, 1, 0
gcd, x, y = extgcd(b, a % b)
return gcd, y, x - a // b * y
A, B = map(int, input().split())
gcd, x, y = extgcd(A, B)
ans = [max(x, 0), max(-x, 0), max(y, 0), max(-y, 0)]
if gcd == 1:
print(*ans)
else:
print(-1)

P110 素数判定
N = int(input())
f = True
i = 2
while i * i <= N:
if N % i == 0:
f = False
i += 1
print("Yes" if f else "No")

P111 素数の個数
import numpy as np
N = int(input())
is_prime = np.full(N + 1, True)
is_prime[0] = is_prime[1] = False
i = 2
while i * i <= N:
if is_prime[i]:
is_prime[i + i :: i] = False
i += 1
print(np.sum(is_prime))

P113 区間内の素数の個数
import numpy as np
A, B = map(int, input().split())
MAX_SQRT_B = 10 ** 6
is_prime = np.full(MAX_SQRT_B + 1, True)
is_prime[0] = is_prime[1] = False
is_prime2 = np.full(B - A, True)
i = 2
while i * i <= B:
if is_prime[i]:
is_prime[i + i :: i] = False
is_prime2[-(-A // i) * i - A : B - A : i] = False
i += 1
print(np.sum(is_prime2))

P114 Carmichael Numbers (UVa No.10006)
N = int(input())
f = False
i = 2
while i * i <= N:
if N % i == 0:
f = True
i += 1
for x in range(1, N):
if pow(x, N, N) != x:
f = False
print("Yes" if f else "No")

P117 Minimum Scalar Product (2008 Round 1A A)
N = int(input())
V1 = list(map(int, input().split()))
V2 = list(map(int, input().split()))
V1.sort()
V2.sort(reverse=True)
ans = 0
for v1, v2 in zip(V1, V2):
ans += v1 * v2
print(ans)

P119 Crazy Rows (2009 Round2 A)
import numpy as np
N = int(input())
M = [input() for _ in range(N)]
A = np.array([m.rfind("1") for m in M])
ans = 0
for i in range(N):
pos = np.where(A[i:] <= i)[0][0] + i
while pos > i:
A[pos], A[pos - 1] = A[pos - 1], A[pos]
pos -= 1
ans += 1
print(ans)

P121 Bribe the Prisoners (2009 Round 1C C)
from functools import lru_cache
@lru_cache
def dfs(res, A):
if len(A) == 2:
return A[1] - A[0] - 1, ()
cost = INF
for i in range(1, len(A) - 1):
cost_l = dfs(A[i] - A[0] - 1, A[: i + 1])[0]
cost_r = dfs(A[-1] - A[i] - 1, A[i:])[0]
cost = min(cost, cost_l + cost_r)
return res + cost, ()
P, Q = map(int, input().split())
A = tuple(map(int, input().split()))
A = (0,) + A + (P + 1,)
INF = 1 << 60
print(dfs(0, A)[0])