[python] ARC107 個人的メモ [Atcoder]
ARC107
所感
BA2完 971パフォ
入緑した
やったぜ
A - Simple Math
最初に見たとき,さっぱりわからなくて焦った
とは言え,B問題の後に見てサンプル1を書いて考えたら割とあっさりわかってよかった
まず総和の公式と言うのがある
これを使って問題の式を解いていくと以下の様に解ける
#!/usr/bin/env python3
A, B, C = map(int, input().split())
MOD = 998244353
c = C * (C + 1) // 2
b = B * (B + 1) // 2
a = A * (A + 1) // 2
print(a * b * c % MOD)
B - Quadruple
abcdをそれぞれで全探索すると
ということで
これならacを全探索すれば,dbはそれぞれの場合で
1つ目の制約より,dbのとれる範囲には限りがあるので,範囲外になる場合は除く
次に
これは,区間1からNに長さ
で,各
公式解説だと,abとcdでセットにしてた
#!/usr/bin/env python3
N, K = map(int, input().split())
ans = 0
for ac in range(1 - N, N):
db = ac - K
if db < 1 - N or N - 1 < db:
continue
ans += (N - abs(ac)) * (N - abs(db))
print(ans)
C - Shuffle Permutation
wa
2つの操作が独立してそうというのは分かったけど,そこから考察がうまいこと進まなかった
unionfindも全然思いつかなかった
列のswapと行のswapの操作は互いに独立している操作だから,両操作の場合の数の積が出力となればおk
制約の3つ目より全ての行列成分が異なると分かる
なので,重複とかは考えなくて良い
まず行のswapについて考える
例えば互いに操作可能な4つの行abcdがあるとする
操作回数に制限はないから,これらの行は好きな順に並べ替えられる
よって,これらの行の組み合わせは
で,他の互いに操作可能な行のグループでも同じように組み合わせを求める
それらの積が最終的に得られる全ての行の組み合わせとなる
同様に列でも全ての組み合わせを求め,行の組み合わせとの積を求めれば解が求まる
互いに操作可能なグループを求めるにはunionfindを用いた
#!/usr/bin/env python3
class UnionFind:
def __init__(self, n: int):
self.root = [-1] * n
def find(self, x: int):
if self.root[x] < 0:
return x
self.root[x] = self.find(self.root[x])
return self.root[x]
def unite(self, x: int, y: int):
x = self.find(x)
y = self.find(y)
if x == y:
return False
if self.root[x] > self.root[y]:
x, y = y, x
self.root[x] += self.root[y]
self.root[y] = x
return True
def same(self, x: int, y: int):
return self.find(x) == self.find(y)
def size(self, x: int) -> bool:
return self.root[self.find(x)] * -1
def main():
from math import factorial
N, K = map(int, input().split())
matrix = [list(map(int, input().split())) for _ in range(N)]
mod = 998244353
row_group = UnionFind(N)
line_group = UnionFind(N)
for i in range(N):
for j in range(i + 1, N):
row = True
line = True
for k in range(N):
if matrix[i][k] + matrix[j][k] > K:
row = False
if matrix[k][i] + matrix[k][j] > K:
line = False
if row:
row_group.unite(i, j)
if line:
line_group.unite(i, j)
ans = 1
for i in range(N):
# root[i]<0というのは,root[i]がグラフの木の根になっているということ
# 要するに同じグループを重複してカウントしないようにしている
if row_group.root[i] < 0:
ans *= factorial(row_group.size(i))
if line_group.root[i] < 0:
ans *= factorial(line_group.size(i))
print(ans % mod)
main()
参考資料
-
[AtCoder] ARC 107 C – Shuffle Permutation | ヤマカサの競技プログラミング
https://yamakasa.net/atcoder-arc-107-c/ -
AtCoder ARC 107 C - Shuffle Permutation (緑色, 500 点) - けんちょんの競プロ精進記録
https://drken1215.hatenablog.com/entry/2020/10/31/234100 -
解説 - AtCoder Regular Contest 107
https://atcoder.jp/contests/arc107/editorial
Discussion