結果
| 問題 |
No.3202 Periodic Alternating Subsequence
|
| コンテスト | |
| ユーザー |
navel_tos
|
| 提出日時 | 2025-07-24 13:22:35 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
AC
|
| 実行時間 | 272 ms / 2,000 ms |
| コード長 | 17,240 bytes |
| コンパイル時間 | 292 ms |
| コンパイル使用メモリ | 82,072 KB |
| 実行使用メモリ | 78,548 KB |
| 最終ジャッジ日時 | 2025-07-24 13:22:42 |
| 合計ジャッジ時間 | 7,099 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 24 |
ソースコード
#yukicoder contest 473 第1回 生成AI作問コンテスト
'''
#A
S = input().split()
print(''.join(Si[0].upper() for Si in S))
#B
N = int(input())
names = [input().split() for _ in range(N)]
#この問題AtCoderで見たな・・・? 名前を座標圧縮
S = []
for Si, Ti in names:
S.append(Si)
S.append(Ti)
back = None
S = [back := Si for Si in sorted(S) if back != Si]
import bisect
names = [(bisect.bisect_left(S, Si), bisect.bisect_left(S, Ti)) for Si, Ti in names]
n = len(S)
C = [0] * n
for Si, Ti in names:
C[Si] += 1
C[Ti] += 1
print('Yes' if all(C[Si] == 1 or C[Ti] == 1 for Si, Ti in names) else 'No')
#C
import bisect
N = int(input())
A = list(map(int, input().split()))
back = None
B = [back := Ai for Ai in sorted(A) if back != Ai]
C = [0] * ( n := len(B) )
for Ai in A:
C[ bisect.bisect_left(B, Ai) ] += 1
for _ in range( Q := int(input()) ):
Xi, Ki = map(int, input().split())
print('Yes' if 0 <= ( i := bisect.bisect_left(B, Xi) ) < n and
B[i] == Xi and C[i] >= Ki else 'No')
#D
#どうしよっかな SegTree使っていい?
#Segment Tree
class SegmentTree:
def __init__(self, N, identity_e, node_f):
self._N, self._size, self._e, self._f = N, 1 << N.bit_length(), identity_e, node_f
self._node = [self._e for _ in range(self._size << 1)]
def build(self, A):
assert len(A) == self._N, 'array too large'
for i, v in enumerate(A, start = self._size): self._node[i] = v
for i in range(self._size - 1, 0, -1):
self._node[i] = self._f( self._node[i << 1], self._node[i << 1 | 1] )
def update(self, i, v):
self._node[i := i + self._size] = v
while (i := i >> 1) != 0:
self._node[i] = self._f( self._node[i << 1], self._node[i << 1 | 1] )
def fold(self, Lt, Rt):
if not 0 <= Lt < Rt <= self._N: return self._e
Lt, Rt, vL, vR = Lt | self._size, Rt + self._size, self._e, self._e
while Lt < Rt:
if Lt & 1: vL = self._f( vL, self._node[Lt] ); Lt += 1
if Rt & 1: Rt -= 1; vR = self._f( self._node[Rt], vR )
Lt >>= 1; Rt >>= 1
return self._f( vL, vR )
ST = SegmentTree( Q := int(input()), 0, max )
Rt = 0
for _ in range(Q):
Ti, Xi = map(int, input().split())
match Ti:
case 1:
ST.update(Rt, Xi)
Rt += 1
case 2:
Lt = Rt - Xi
print(ST.fold(Lt, Rt))
#E
#複雑だな 鍵を持っていない状態を0としたいから・・・
#通路を0 鍵を1 ~ 9 扉を11 ~ 19 壁を20 に対応させればいいかな
H, W, M = map(int, input().split())
l = W.bit_length()
B = bytearray(H + 1 << l)
for i in range( len(B) ): B[i] = 20
for h in range(H):
for w, Shw in enumerate(input().rstrip()):
i = h << l | w
if Shw == '.': B[i] = 0
elif Shw == '#': B[i] = 20
elif Shw == 'S': B[i] = 0; st = i
elif Shw == 'G': B[i] = 0; gl = i
elif Shw in '123456789': B[i] = int(Shw)
elif Shw in 'abcdefghi': B[i] = 11 + ord(Shw) - ord('a')
else: assert False
#DP[i][f]: 現在値がi、鍵がfとなるような最短経路
m = M.bit_length()
DP = [10 ** 9] * (len(B) << m)
DP[st << m | 0] = 0
maskm = ~ ( - 1 << m )
Q, R = [], [st << m | 0]
dist = -1
while R:
Q, R = R, Q
dist += 1
while Q:
x = Q.pop()
if DP[x] < dist: continue
DP[x] = dist
i, f = x >> m, x & maskm
for t in -1, 1, 1 << l, -1 << l:
if B[j := i + t] == 20: continue
if B[j] == 0: g = f
elif 1 <= B[j] <= 9: g = B[j]
elif 11 <= B[j] <= 19:
if f != B[j] - 10: continue
else: g = f
if DP[j << m | g] > dist + 1:
DP[j << m | g] = dist + 1
R.append(j << m | g)
ans = min(DP[gl << m | f] for f in range(M + 1))
print(ans if ans != 10 ** 9 else -1)
#F
#UnionFind
class UnionFind:
def __init__(self, N: int): self._parent = [-1] * N
def find(self, Vi: int):
Pi = Vi #2個目のwhileは parent[Vi], Vi の順で並列代入すること
while self._parent[Pi] >= 0: Pi = self._parent[Pi]
while Pi != Vi: self._parent[Vi], Vi = Pi, self._parent[Vi]
return Pi
def unite(self, Ui: int, Vi: int):
if ( Ui := self.find(Ui) ) == ( Vi := self.find(Vi) ): return False
if self._parent[Ui] > self._parent[Vi]: Ui, Vi = Vi, Ui
self._parent[Ui] += self._parent[Vi]; self._parent[Vi] = Ui
return True
def same(self, Ui: int, Vi: int): return self.find(Ui) == self.find(Vi)
def size(self, Vi: int): return - self._parent[ self.find(Vi) ]
#入力受取
N, M = map(int, input().split())
edges = [tuple(map(lambda x: int(x) - 1, input().split())) for _ in range(M)]
Q = int(input())
B = [int(input()) - 1 for _ in range(Q)]
UF = UnionFind(N)
bloken = bytearray(M)
for Bi in B: bloken[Bi] = 1
for i, (Ui, Vi) in enumerate(edges):
if not bloken[i]: UF.unite(Ui, Vi)
del bloken
cnt = N * (N - 1) >> 1
for i in range(N):
if i == UF.find(i): cnt -= UF.size(i) * (UF.size(i) - 1) >> 1
ans = [0] * Q
ans[-1] = cnt
for i in range(Q - 1, -1, -1):
Ui, Vi = edges[Bi := B[i]]
if not UF.same(Ui, Vi):
sizeUi, sizeVi = UF.size(Ui), UF.size(Vi)
cnt -= sizeUi * sizeVi
UF.unite(Ui, Vi)
if i:
ans[i - 1] = cnt
print(*ans, sep = '\n')
#G
#最大流(Dinic法 stack DFS) 配列を完全一次元化
#Reference: https://atcoder.jp/contests/abc285/submissions/42876297
class maxflow:
\'''
燃やす埋める: S → A/B → G, S → Aを切るならS → Bも切る は A → B(inf)
最小流量制限: A → B(Lt ~ Rt)
A → B(Rt - Lt), St2 → B(Lt), A → Gl2(Lt) の辺を代わりに張る。
St2 → Gl2, St2 → Gl, St → Gl2, St → Gl の順に流し、St2, Gl2の辺がcap = 0ならOK
---
G[now]: (頂点nowに起始する辺番号)の二次元配列を回避し、定数倍高速化を目指します。
順辺の個数は self.M で取得できます。
\'''
def __init__(self, N: int, inf = '4 * 10 ** 18'):
#E[i << 1], E[i << 1 | 1]: i番目の順辺のnow, nxt
#C[i]: cap
#P[i]: post : 辺番号iの起始をnowとしたとき、nowの前の辺番号
# 二次元配列との対比: G[now] = [・・・, P[i], i ・・・]のように、iの前の辺がP[i]
#B[now]: base : 頂点nowのイテレート開始辺 len(G[now]) == 0の場合、B[now] = -1
self.N, self.M = N, 0
self.inf = max( 0, inf ) if type(inf) != str else 4 * 10 ** 18
self._E, self._C, self._P, self._B, self._A = [], [], [], [-1] * N, [-1] * N
self._D, self._F, self._L, self._Q = [N] * N, [0] * N, [0] * N, [0] * N
#最大流計算の主要部
def _calc(self, St, Gl, permissible_error, flow_limit):
#D[now]: D[St]からの最短距離
#F[now]: flow, L[now]: leak 頂点nowに流入したフロー・流出が確定したフロー
#queue, stack: 同一配列を参照 BFSではdequeの代用 DFSでは非再帰化に用いる
#A[now]: arrow : 頂点nowがちょうど今見ている辺番号 A[now] == -1はStopIteration
N, E, C, P, B, A = self.N, self._E, self._C, self._P, self._B, self._A
D, F, L, queue, stack = self._D, self._F, self._L, self._Q, self._Q
flow_limit = max( 0, flow_limit ) if type(flow_limit) != str else self.inf
pe, flow = max( 0, permissible_error ), 0
#Dual-Primal step
while flow_limit > flow:
#Phase 1. BFS
for now in range(N): D[now] = N #初期化
D[St], queue[ Rt := 0 ] = 0, St
for Lt, now in enumerate( queue ):
A[now], x = B[now], D[now] + 1 #BFS出現辺のみA[now]を初期化
if ( i := B[now] ) != -1: #出次数が0の場合はB[now] == -1となる
while i != -1:
if C[i] > pe and D[ nxt := E[i ^ 1] ] > x:
D[nxt], queue[ Rt := Rt + 1 ] = x, nxt
i = P[i]
if Lt == Rt or now == Gl: break
if D[Gl] == N: break #BFSで到達不可能
#Phase 2. St ← Gl方向にDFS
F[Gl], L[Gl], stack[ d := 0 ] = flow_limit - flow, 0, Gl
while True: #F, Lの初期化は入りがけに行う
if ( now := stack[d] ) == Gl and F[Gl] == L[Gl]: return flow + L[Gl]
if now == St or F[now] == L[now]:
#(St側) now → back (Gl側) に流量 F[now] := 届いた分全部 を流す
back, f = stack[ d := d - 1 ], F[now]
C[ i := A[back] ] += f; C[i ^ 1] -= f; L[back] += f; continue
#(St側) nxt → now → back (Gl側) と流したい 残容量のある逆辺を探す
x = D[now] - 1
while ( i := A[now] ) != -1:
#DFS成功時は辺番号を変えず潜る 失敗時と帰りがけに辺番号を上げる
if x == D[ nxt := E[i ^ 1] ] and ( r_cap := C[i ^ 1] ) > pe:
F[nxt], L[nxt] = min( F[now] - L[now], r_cap ), 0
stack[ d := d + 1 ] = nxt; break
else: A[now] = P[i]
else: #帰りがけの処理
assert A[now] == -1
if now == Gl: flow += L[now]; break #pop Glの代用
#(St側) now → back (Gl側) に流量 L[now] := now以降で流した量 を流す
back = stack[ d := d - 1 ]
C[ i := A[back] ] += ( f := L[now] )
C[i ^ 1] -= f; L[back] += f; A[back] = P[i]
return flow
#辺の追加・取得
def add_edge(self, From: int, To: int, cap):
assert From in range(self.N) and To in range(self.N) and 0 <= cap
self._P.append( i := len(self._E) ); self._E.append(From); self._C.append(cap)
self._P.append( j := len(self._E) ); self._E.append( To ); self._C.append( 0 )
self._B[From], self._P[i] = self._P[i], self._B[From]
self._B[ To ], self._P[j] = self._P[j], self._B[ To ]; self.M += 1
def get_edge(self, i: int): #i番目の順辺の now, nxt, cap(順辺), rev_cap(逆辺)
assert i in range( self.M )
return self._E[i << 1], self._E[i << 1 | 1], self._C[i << 1], self._C[i << 1 | 1]
#最大流を計算 許容誤差: 残余容量がper_error以下の辺は容量0とみなす
def calc(self, start: int, goal: int, permissible_error = 0, flow_limit = 'infinity'):
assert start in range(self.N) and goal in range(self.N) and start != goal
return self._calc(start, goal, permissible_error, flow_limit)
#辺容量がすべて整数の場合に限り、O(NMlogC)で解ける
def calc_int(self, start: int, goal: int, max_capacity: int = 'infinity'):
assert start in range(self.N) and goal in range(self.N) and start != goal
m = max_capacity if type(max_capacity) != str else int( self.inf )
ans, logm = 0, max( 0, round(m) ).bit_length()
for e in range( logm, -1, -1 ): ans += self.calc( start, goal, (1 << e) - 1 )
return ans
#入力受取
N = int(input())
P = list(map(int, input().split()))
M = int(input())
terms = [tuple(map(lambda x: int(x) - 1, input().split())) for _ in range(M)]
K = int(input())
combs = [None] * K
for k in range(K):
Ai, Bi, Si = map(int, input().split())
combs[k] = (Ai - 1, Bi - 1, Si)
#燃やす埋める問題に帰着したい
#St側を「採用」 Gl側を「あきらめる」にしよう
#単独事業: すべての利益を先に得ておくと、すべてを罰金で処理できる
#依存関係: St → A を諦めるなら St → B も諦める、はA → B(inf)
# なので Ui → Vi(inf) を張る
#シナジー: うまい辺の張り方が思いつかない・・・
# 利益を先に計上しておいて、Ai, Bi → シナジー頂点(inf) を張る?
MF = maxflow(N + K + 2)
ans = 0
St, Gl = N + K, N + K + 1
for i, Pi in enumerate(P):
if Pi >= 0:
ans += Pi
MF.add_edge(i, Gl, Pi)
else:
MF.add_edge(St, i, abs(Pi))
for Ui, Vi in terms:
MF.add_edge(Ui, Vi, MF.inf)
for k, (Ai, Bi, Si) in enumerate(combs, start = N):
ans += Si
MF.add_edge(k, Gl, Si)
MF.add_edge(Ai, k, MF.inf)
MF.add_edge(Bi, k, MF.inf)
print(ans - MF.calc_int(St, Gl))
'''
#H
#行列累乗 1行N列の行列は [ [1, 2, ...] ] と二重括弧に変換し、演算はすべて非破壊的
class matrix_pow:
def __init__(self, MOD = 998244353): self.MOD = MOD
def eye(self, N: int): #単位行列
return [ [1 if i == j else 0 for j in range(N)] for i in range(N) ]
def add(self, A, B): #行列の加算
if isinstance( A[0], int ): A = [ A ]
if isinstance( B[0], int ): B = [ B ]
assert len(A) == len(B) and len(A[0]) == len(B[0]), 'not same size'
G = [[] for _ in range( len(A) )]
for h in range( len(G) ):
G[h] = [0] * max( len(A[h]), len(B[h]) )
for w in range( len(A[h]) ): G[h][w] = A[h][w] % self.MOD
for w in range( len(B[h]) ): G[h][w] = (G[h][w] + B[h][w]) % self.MOD
return G
def mul(self, A, B): #行列の積算 H行X列 * X行W列 = H行W列
if isinstance( A[0], int ): A = [ A ]
if isinstance( B[0], int ): B = [ B ]
assert len(A[0]) == len(B), 'cannnot calcurate'
G = [[0] * max( len(Bi) for Bi in B ) for _ in range( len(A) )]
for h in range( len(G) ):
for w, n in enumerate( G[h] ):
for x in range( len(A[0]) ): n += A[h][x] * B[x][w] % self.MOD
G[h][w] = n % self.MOD #最後にまとめて除算
return G
def doubling_mul(self, A, t): #A ^ tを計算
if isinstance( A[0], int ): A = [ A ]
assert all( len(Ai) == len(A) for Ai in A ) and t >= 0, 'cannot calcurate'
N, M = len(A), self.MOD
G, B, C = self.eye(N), [Ai[:] for Ai in A], [[0] * N for _ in range(N)]
while True:
if t & 1: #if t & 1: G = self.mul(G, B)
for h in range(N):
for w in range(N):
C[h][w] = sum( G[h][x] * B[x][w] % M for x in range(N) ) % M
G, C = C, G
if (t := t >> 1) == 0: break
for h in range(N): #B = self.mul(B, B)
for w in range(N):
C[h][w] = sum( B[h][x] * B[x][w] % M for x in range(N) ) % M
B, C = C, B
return G
#入力受取
T = bytearray(int(Ti) for Ti in input().rstrip())
K = int(input())
MOD = 10 ** 9 + 7
def brute(T, K):
ans = 0
newT = T * K
n = len(newT)
for S in range(1 << n):
U = []
for i in range(n):
if S >> i & 1: U.append(newT[i])
if all(U[k] != U[k + 1] for k in range(len(U) - 1)):
ans += len(U) ** 2
return ans
#まずは愚直なDPを考える
#DP[i][s][f]: i文字目まで見て、最後に採用した文字がs、赤玉を入れた個数がf個の場合の数
def brute_2(T, K):
newT = T * K
n = len(newT)
DP = [[[0] * 3 for _ in range(2)] for _ in range(n + 1)]
DP[0][0][0] = DP[0][1][0] = 1
for i, Ti in enumerate(newT):
for s in range(2):
for f in range(3):
DP[i + 1][s][f] += DP[i][s][f]
if Ti == 0:
DP[i + 1][Ti][0] += DP[i][1][0]
DP[i + 1][Ti][1] += 2 * DP[i][1][0] + DP[i][1][1]
DP[i + 1][Ti][2] += DP[i][1][0] + DP[i][1][1] + DP[i][1][2]
else:
DP[i + 1][Ti][0] += DP[i][Ti ^ 1][0]
DP[i + 1][Ti][1] += 2 * DP[i][Ti ^ 1][0] + DP[i][Ti ^ 1][1]
DP[i + 1][Ti][2] += DP[i][Ti ^ 1][0] + DP[i][Ti ^ 1][1] + DP[i][Ti ^ 1][2]
for s in range(2):
for f in range(2):
DP[i + 1][s][f] %= MOD
return sum(DP[-1][s][2] for s in range(2)) % MOD
#合ってそう なので1周期あたりの遷移を構築する
def make_grid(T):
#DP[s][t]: s → t の遷移 mod 10 ** 9 + 7
#状態は f << 1 | Ti で表せば6状態になるはず
DP = []
for st in range(6):
dp = [[0] * 2 for _ in range(3)]
ndp = [[0] * 2 for _ in range(3)]
dp[st >> 1][st & 1] = 1
for Ti in T:
for f in range(3):
for s in range(2): ndp[f][s] = dp[f][s]
ndp[0][Ti] += dp[0][Ti ^ 1]
ndp[1][Ti] += dp[0][Ti ^ 1] * 2 + dp[1][Ti ^ 1]
ndp[2][Ti] += dp[0][Ti ^ 1] + dp[1][Ti ^ 1] + dp[2][Ti ^ 1]
ndp[0][Ti] %= MOD
ndp[1][Ti] %= MOD
ndp[2][Ti] %= MOD
dp, ndp = ndp, dp
DP.append([dp[gl >> 1][gl & 1] for gl in range(6)])
return DP
def solve(T, K):
MP = matrix_pow(MOD)
DP = make_grid(T)
DP = MP.doubling_mul(DP, K)
ans = [[1, 1, 0, 0, 0, 0]]
ans = MP.mul(ans, DP)[0]
return ( ans[2 << 1 | 0] + ans[2 << 1 | 1] ) % MOD
print(solve(T, K))
navel_tos