結果
| 問題 |
No.3201 Corporate Synergy
|
| コンテスト | |
| ユーザー |
👑 Kazun
|
| 提出日時 | 2025-07-11 23:10:58 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
AC
|
| 実行時間 | 95 ms / 2,000 ms |
| コード長 | 14,862 bytes |
| コンパイル時間 | 220 ms |
| コンパイル使用メモリ | 81,912 KB |
| 実行使用メモリ | 77,420 KB |
| 最終ジャッジ日時 | 2025-07-11 23:11:01 |
| 合計ジャッジ時間 | 2,534 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 20 |
ソースコード
#Thansk for aaaaaaaaaa2230
#URL: https://atcoder.jp/contests/practice2/submissions/17017372
from collections import deque
class Arc:
def __init__(self, source: int, target: int, cap: int, base: int, direction: int, id: int):
self.source = source
self.target = target
self.cap = cap
self.base = base
self.rev: Arc = None
self.direction = direction # 1 が順, -1 が逆順
self.id = id
def __repr__(self):
return f"{self.__class__.__name__}(source={self.source}, target={self.target}, cap={self.cap}, base={self.base}, direction={self.direction}, id={self.id})"
class Max_Flow:
inf = float("inf")
def __init__(self, N: int = 0):
""" N 頂点の最大フローを用意する.
Args:
N (int, optional): 位数. Defaults to 0.
"""
self.arc: list[list[Arc]] = [[] for _ in range(N)]
self.__arc_list: list[Arc] =[]
@property
def order(self) -> int:
""" 位数
Returns:
int: 位数
"""
return len(self.arc)
@property
def vertex_count(self) -> int:
""" 頂点数
Returns:
int: 頂点数
"""
return len(self.arc)
@property
def size(self) -> int:
""" サイズ
Returns:
int: サイズ
"""
return len(self.__arc_list)
@property
def arc_count(self):
""" 弧の数
Returns:
int: 弧の数
"""
return len(self.__arc_list)
def add_vertex(self) -> int:
""" 頂点を 1 個追加する.
Returns:
int: 追加した頂点の番号
"""
self.arc.append([])
return self.vertex_count - 1
def add_vertices(self, k: int) -> int:
""" 頂点を k 個追加する.
Args:
k (int): 追加する頂点の数
Returns:
int: 追加する k 個の頂点の番号からなるリスト
"""
n = self.vertex_count
self.arc.extend([[] for _ in range(k)])
return list(range(n, n + k))
def add_arc(self, v: int, w: int, cap: int) -> int:
""" 容量 cap の弧 v → w を追加する.
Args:
v (int): 始点
w (int): 終点
cap (int): 容量
Returns:
int: 追加した弧の番号
"""
m = self.size
arc = Arc(v, w, cap, cap, 1, m)
arc_rev = Arc(w, v, 0, cap, -1, m)
arc.rev = arc_rev
arc_rev.rev = arc
self.arc[v].append(arc)
self.arc[w].append(arc_rev)
self.__arc_list.append(arc)
return m
def get_arc(self, i: int) -> Arc:
""" i 番目の弧を得る.
Args:
i (int): 弧の番号
Returns:
Arc: 弧
"""
assert 0 <= i < self.size
return self.__arc_list[i]
def get_all_arcs(self) -> list[Arc]:
return [self.get_arc(i) for i in range(self.size)]
def change_arc(self, i, new_cap, new_flow):
""" i 番目の辺の情報を変更する.
"""
assert 0 <= i < self.size
assert 0 <= new_flow<=new_cap
a=self.__arc_list[i]
a.base=new_cap; a.cap=new_cap-new_flow
a.rev.base=new_cap; a.rev.cap=new_flow
def add_edge(self, v, w, cap):
""" 容量 cap の無向辺 v → w を加える."""
self.add_arc(v,w,cap)
self.add_arc(w,v,cap)
def __bfs(self, s: int, t: int) -> bool:
level = self.level = [-1] * self.vertex_count
Q = deque([s])
level[s] = 0
while Q:
v = Q.popleft()
next_level = level[v] + 1
for arc in self.arc[v]:
if not(arc.cap and level[arc.target] == -1):
continue
level[arc.target] = next_level
if arc.target == t:
return True
Q.append(arc.target)
return False
def __dfs(self, s: int, t: int, up: int) -> int:
arc_to = self.arc
it = self.it
level = self.level
st = deque([t])
while st:
v = st[-1]
if v == s:
break
lv = level[v]-1
while it[v] < len(arc_to[v]):
arc_rev = arc_to[v][it[v]]
arc = arc_rev.rev
if arc.cap == 0 or lv != level[arc.source]:
it[v] += 1
continue
st.append(arc.source)
break
if it[v] == len(arc_to[v]):
st.pop()
level[v] = -1
else:
return 0
st.pop()
flow = up
for w in st:
arc = arc_to[w][it[w]].rev
flow = min(flow, arc.cap)
for w in st:
arc_rev = arc_to[w][it[w]]
arc_rev.cap += flow
arc_rev.rev.cap -= flow
return flow
def max_flow(self, source: int, target: int, flow_limit: int = inf) -> int:
""" source から target へ flow_limit を上限として流せるだけ流したときの "追加で発生する" 流量を求める.
Args:
source (int): 始点
target (int): 終点
flow_limit (int, optional): 流量の上限. Defaults to inf.
Returns:
int: "追加で発生する" 流量
"""
flow = 0
while flow < flow_limit and self.__bfs(source, target):
self.it = [0] * self.vertex_count
while flow < flow_limit:
f = self.__dfs(source, target, flow_limit - flow)
if f == 0:
break
flow += f
return flow
def get_flow(self) -> list[list[tuple[int, int, int]]]:
F = [[] for _ in range(self.vertex_count)]
for arc in self.__arc_list:
F[arc.source].append((arc.id, arc.target, arc.base - arc.cap))
return F
def min_cut(self, s: int) -> list[int]:
""" s を 0 側に含める最小カットを求める.
Args:
s (int): 頂点番号
Returns:
list[int]: 0, 1 からなる長さが位数のリスト. 最小カットは 0 側と 1 側に分かれる. 頂点 s は必ず 0 側になる.
"""
group = [1] * self.vertex_count
Q = deque([s])
while Q:
v = Q.pop()
group[v] = 0
for arc in self.arc[v]:
if arc.cap and group[arc.target]:
Q.append(arc.target)
return group
def refresh(self):
for a in self.__arc_list:
a.cap = a.base
a.rev.cap = 0
inf=float("inf")
class Project_Selection_Problem:
def __init__(self, N = 0):
""" N 要素の Project Selection Problem を生成する.
N: int
"""
self.N = N
self.ver_num = N + 2
self.base = 0
self.source = N
self.target = N + 1
self.indivi = [[0, 0] for _ in range(N + 2)]
self.mutual: list[tuple[int, int, int]] = []
def add_vertex(self) -> int:
""" 変数を 1 個追加する.
Returns:
int: 追加した頂点の番号
"""
n = self.ver_num
self.indivi.append([0,0])
self.ver_num += 1
return n
def __add_vertex_inner(self):
n = self.ver_num
self.indivi.append([None, None])
self.ver_num += 1
return n
def add_vertices(self, k: int) -> int:
""" 変数を k 個追加する.
Args:
k (int): 追加する頂点の番号
Returns:
int: 追加した k 個の頂点番号からなるリスト
"""
n = self.ver_num
self.indivi.extend([[0, 0] for _ in range(k)])
self.ver_num += k
return list(range(n, n + k))
def set_zero_one(self, x: int, y: int, a: int):
""" 「h(x) = 0, h(y) = 1 のとき, a (<=0) 点を得る」という観点を追加する.
Args:
x (int): h(x) = 0 を課す変数の番号
y (int): h(y) = 1 を課す変数の番号
a (int): 観点の得点 (負でなくてはならない)
"""
assert 0 <= x < self.N
assert 0 <= y < self.N
assert a <= 0, f"a は負でなくてはなりません (a = {a})"
self.mutual.append((x, y, -a))
def set_zero(self, x: int, a: int):
""" 「h(x) = 0 のとき, a 点を得る」という観点を追加する.
Args:
x (int): h(x) = 0 を課す変数の番号
a (int): 観点の得点
"""
assert 0 <= x < self.N
self.indivi[x][0] += a
def set_one(self, x: int, a: int):
""" 「h(x) = 1 のとき, a 点を得る」という観点を追加する.
Args:
x (int): h(x) = 1 を課す変数の番号
a (int): 観点の得点
"""
assert 0 <= x < self.N
self.indivi[x][1] += a
def set_all_zero(self, X: list[int], a: int):
""" 「h(x) = 0 (forall x in X) のとき, a (>= 0) 点を得る」という観点を追加する.
Args:
X (list[int]): 変数の番号のリスト
a (int): 観点の得点 (正でなくてはならない)
"""
assert a >= 0, f"a は正でなくてはなりません (a = {a})"
k = self.__add_vertex_inner()
self.base += a
self.indivi[k][0] = -a
for x in X:
assert 0 <= x < self.N
self.mutual.append((k, x, inf))
def set_all_one(self, X: list[int], a: int):
""" 「h(x) = 1 (forall x in X) のとき, a (>= 0) 点を得る」という観点を追加する.
Args:
X (list[int]): 変数の番号のリスト
a (int): 観点の得点 (正でなくてはならない)
"""
assert a >= 0, f"a は正でなくてはなりません (a = {a})"
k = self.__add_vertex_inner()
self.base += a
self.indivi[k][1] = -a
for x in X:
assert 0 <= x < self.N
self.mutual.append((x, k, inf))
def set_not_equal(self, x:int, y: int, a: int):
""" 「h(x) != h(y) のとき, a (<= 0) 点を得る」という観点を追加する.
Args:
x (int):
y (int):
a (int): 観点の得点 (負でなくてはならない)
"""
assert 0 <= x < self.N
assert 0 <= y < self.N
assert a <= 0, f"a は負でなくてはなりません (a = {a})"
self.set_zero_one(x, y, a)
self.set_zero_one(y, x, a)
def set_equal(self,x,y,a):
""" 「h(x) = h(y) のとき, a (>= 0) 点を得る」という観点を追加する.
Args:
x (int):
y (int):
a (int): 観点の得点 (正でなくてはならない)
"""
assert 0 <= x < self.N
assert 0 <= y < self.N
assert a >= 0, f"a は負でなくてはなりません (a = {a})"
self.set_all_zero([x, y], a)
self.set_all_one([x, y], a)
def ban_zero(self, x: int):
""" h(x) = 0 となることを禁止する (実行したら -inf 点になる)
Args:
x (int): h(x) = 0 を禁止する変数の番号
"""
assert 0 <= x < self.N
self.set_zero(x, -inf)
def ban_one(self, x: int):
""" h(x) = 1 となることを禁止する (実行したら -inf 点になる).
Args:
x (int): h(x) = 1 を禁止する変数の番号
"""
assert 0 <= x < self.N
self.set_one(x, -inf)
def force_zero(self, x: int):
""" h(x) = 0 を絶対条件にする (要するに, ban_one(x)).
Args:
x (int): h(x) = 0 を指定する変数の番号
"""
assert 0 <= x < self.N
self.ban_one(x)
def force_one(self, x: int):
""" h(x) = 1 を絶対条件にする (要するに, ban_zero(x)).
Args:
x (int): h(x) = 1 を指定する変数の番号
"""
assert 0 <= x < self.N
self.ban_zero(x)
def increase(self, X: list[int]):
""" h(x[0]) <= h(x[1]) <= ... <= h(x[k-1]) (h(x[i]) = 1, h(x[i+1]) = 0 を禁止) という条件を追加する.
Args:
X (list[int]): 単調性を課す変数の番号のリスト
"""
for i in range(len(X) - 1):
self.set_zero_one(X[i + 1], X[i], -inf)
def decrease(self, X: list[int]):
""" h(x[0]) >= h(x[1]) >= ... >= h(x[k-1]) (h(x[i]) = 0, h(x[i+1]) = 1 を禁止) という条件を追加する.
Args:
X (list[int]): 単調性を課す変数の番号のリスト
"""
self.increase(X[::-1])
def solve(self):
""" Project Selection Problem を解く. """
F = Max_Flow(self.ver_num)
base= self.base
for i in range(self.N):
F.add_arc(self.source, i, 0)
F.add_arc(i, self.target, 0)
if self.indivi[i][0] >= 0:
base += self.indivi[i][0]
F.add_arc(self.source, i, self.indivi[i][0])
else:
F.add_arc(i, self.target, -self.indivi[i][0])
if self.indivi[i][1] >= 0:
base += self.indivi[i][1]
F.add_arc(i, self.target, self.indivi[i][1])
else:
F.add_arc(self.source, i, -self.indivi[i][1])
for i in range(self.target + 1, self.ver_num):
if self.indivi[i][0] is not None:
F.add_arc(self.source, i, -self.indivi[i][0])
if self.indivi[i][1] is not None:
F.add_arc(i, self.target, -self.indivi[i][1])
for x, y, c in self.mutual:
F.add_arc(x, y, c)
alpha = F.max_flow(self.source, self.target)
self.__ans = base - alpha
self.__choice = F.min_cut(self.source)
@property
def ans(self):
return self.__ans
@property
def choice(self):
return self.__choice
#==================================================
def solve():
N = int(input())
F = Project_Selection_Problem(N + 1)
P = [0] + list(map(int, input().split()))
for i in range(1, N + 1):
F.set_one(i, P[i])
M = int(input())
inf = pow(10, 18)
for _ in range(M):
u, v = map(int, input().split())
F.set_zero_one(u, v, -inf)
K = int(input())
for _ in range(K):
a, b, s = map(int, input().split())
F.set_all_one([a, b], s)
F.solve()
return F.ans
#==================================================
print(solve())
Kazun