結果
問題 | No.3119 A Little Cheat |
ユーザー |
![]() |
提出日時 | 2025-04-20 03:40:08 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 193 ms / 2,000 ms |
コード長 | 4,130 bytes |
コンパイル時間 | 731 ms |
コンパイル使用メモリ | 82,724 KB |
実行使用メモリ | 104,028 KB |
最終ジャッジ日時 | 2025-04-20 03:40:19 |
合計ジャッジ時間 | 8,969 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 49 |
ソースコード
""" https://yukicoder.me/problems/no/3119 2増える or 1増える or 変化なし 増えるものはいくつあるか?を数え上げればいい? 2増える場合は A[i] < B[i+1] A[i+1] < B[i] A[i] >= B[i] A[i+1] >= B[i+1] これは存在しない 1増える場合 B[i] <= A[i] < B[i+1] <= A[i+1] OR B[i+1] <= A[i+1] < B[i] <= A[i] なら成立 dp[i][既にあるか?][ B[i-1]<A[i-1]か? ] でdpすれば行けそう? 2つ同時に決めないとダメかなぁ いや、増えないものを数え上げたほうがいい dp[i][次で違反の可能性があるか?] で良いのかなぁ 1 2 1 2,3,4 -> 違反できる 1,1 : Y 1,2 : 違反 1,3 : N 1,4 : N 2,1 : Y 2,2 : Y 2,3 : N 2,4 : N 3,1 : Y 3,2 : Y 3,3 : N 3,4 : N 4,1 : Y 4,2 : Y 4,3 : N 4,4 : N 8*4 = 32 1 2 3 2 3 1 7 * 1 --- 既に片側満たしているのが、両側になることがある? A[i] < B[i+1] < A[i+1] < B[i] A[i+1] < B[i] < A[i] < B[i+1] あるなー B[i] <= A[i] < B[i+1] <= A[i+1] A[i] < B[i+1] <= A[i+1] < B[i] B[i+1] <= A[i+1] < B[i] <= A[i] A[i+1] < B[i] <= A[i] < B[i+1] の4つの条件をまとめたい """ # LR1の範囲からLR2の区間を取り除いた長さ def sub( L1,R1,L2,R2 ): if L1 > R1: assert False if L2 > R2: assert False if L2 <= L1 and R1 <= R2: return 0 elif R2 < L1 or R1 < L2: return R1-L1+1 else: return max(0,L2-L1) + max(0,R1-R2) #LR1とLR2の区間の重複長さを返す def mul( L1,R1,L2,R2 ): if L1 > R1: return 0 if L2 > R2: return 0 R = min(R1,R2) L = max(L1,L2) return max(0, R-L+1) mod = 998244353 N,M = map(int,input().split()) A = list(map(int,input().split())) # dp[0] = 次違反する可能性がない # dp[1] = 次違反する可能性がある if A[0] < A[1]: dp = [ A[1]-A[0] , M-(A[1]-A[0]) ] elif A[1] < A[0]: dp = [ M-(A[0]-A[1]) , A[0]-A[1] ] else: dp = [ M , 0 ] # 同じ値を置くことで、番兵とする A.append(A[-1]) # print (dp) for i in range(1,N): ndp = [0,0] # 違反の危険性がない場合、後ろだけを見て決められる D = abs(A[i+1]-A[i]) if A[i] < A[i+1]: ndp[0] += D * dp[0] ndp[1] += (M-D) * dp[0] elif A[i+1] < A[i]: ndp[0] += (M-D) * dp[0] ndp[1] += D * dp[0] else: ndp[0] += M * dp[0] # 違反の可能性がある場合は、大小関係で場合分け... if A[i-1] < A[i]: # A[i-1] < B[i] <= A[i] は設置禁止 XL = A[i-1] + 1 XR = A[i] if A[i] < A[i+1]: # A[i]より大きい位置に配置する場合 ndp[0] += sub(A[i]+1,A[i+1],XL,XR) * dp[1] # A[i-1]以下に設置する場合 ndp[1] += ( sub(1,A[i],XL,XR) + sub(A[i+1]+1,M,XL,XR) ) * dp[1] elif A[i] > A[i+1]: ndp[0] += ( sub(1,A[i+1],XL,XR) + sub(A[i]+1,M,XL,XR) ) * dp[1] ndp[1] += sub(A[i+1]+1,A[i],XL,XR) * dp[1] else: # A[i] == A[i+1] ndp[0] += sub(1,M,XL,XR) * dp[1] elif A[i-1] > A[i]: # B[i+1] <= A[i+1] < B[i] <= A[i] < B[i+1] # 逆に、許可の区間が XL~XR XL = A[i] + 1 XR = A[i-1] if A[i] < A[i+1]: ndp[0] += mul(A[i]+1,A[i+1],XL,XR) * dp[1] ndp[1] += ( mul(1,A[i],XL,XR) + mul(A[i+1]+1,M,XL,XR) ) * dp[1] elif A[i] > A[i+1]: ndp[1] += mul(A[i+1]+1,A[i],XL,XR) * dp[1] ndp[0] += ( mul(1,A[i+1],XL,XR) + mul(A[i]+1,M,XL,XR) ) * dp[1] else: ndp[0] += mul(1,M,XL,XR) * dp[1] else: # dp[1] = 0のはずなので pass dp = [x % mod for x in ndp] # print (dp) # 動かさない場合のスコア X = pow(M,N-1,mod) base = 0 for i in range(N): base += (M-A[i]) * X base %= mod # print (base , pow(M,N,mod) ,- dp[0]) ans = (base + pow(M,N,mod) - dp[0]) % mod print (ans)