結果
問題 | No.1191 数え上げを愛したい(数列編) |
ユーザー | persimmon-persimmon |
提出日時 | 2021-06-18 11:13:16 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 159 ms / 2,000 ms |
コード長 | 2,659 bytes |
コンパイル時間 | 226 ms |
コンパイル使用メモリ | 82,320 KB |
実行使用メモリ | 155,592 KB |
最終ジャッジ日時 | 2024-06-22 01:20:23 |
合計ジャッジ時間 | 3,479 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 93 ms
118,304 KB |
testcase_01 | AC | 133 ms
137,632 KB |
testcase_02 | AC | 121 ms
142,552 KB |
testcase_03 | AC | 116 ms
128,048 KB |
testcase_04 | AC | 146 ms
154,200 KB |
testcase_05 | AC | 88 ms
109,888 KB |
testcase_06 | AC | 156 ms
138,592 KB |
testcase_07 | AC | 137 ms
152,880 KB |
testcase_08 | AC | 137 ms
153,388 KB |
testcase_09 | AC | 132 ms
153,480 KB |
testcase_10 | AC | 128 ms
151,088 KB |
testcase_11 | AC | 129 ms
150,376 KB |
testcase_12 | AC | 130 ms
137,360 KB |
testcase_13 | AC | 132 ms
137,724 KB |
testcase_14 | AC | 159 ms
155,592 KB |
testcase_15 | AC | 31 ms
52,596 KB |
testcase_16 | AC | 29 ms
52,824 KB |
testcase_17 | AC | 31 ms
53,504 KB |
testcase_18 | AC | 32 ms
52,204 KB |
testcase_19 | AC | 31 ms
52,916 KB |
testcase_20 | AC | 28 ms
52,960 KB |
testcase_21 | AC | 29 ms
52,340 KB |
testcase_22 | AC | 89 ms
117,360 KB |
testcase_23 | AC | 30 ms
53,252 KB |
testcase_24 | AC | 29 ms
53,080 KB |
testcase_25 | AC | 30 ms
53,224 KB |
ソースコード
def main0(n,m,a,b): mod=998244353 dp=[0]*(b+1) dp[0]=1 for _ in range(n-1): ndp=[0]*(b+1) for i in range(b+1): for j in range(a,b+1): if i+j>b:continue ndp[i+j]+=dp[i] ndp[i+j]%=mod dp=ndp ans=0 for i in range(1,m+1): # 初項がiの場合、最終項はi+bまでOK # これがm以下ならsum(dp) # mを超えたらsum(dp[:-(i+b-m)]) if i+b<=m: ans+=sum(dp)%mod else: ans+=sum(dp[:-(i+b-m)])%mod for i in range(1,n+1): ans=ans*i%mod return ans # 任意の二項の差の絶対値はa以上b以下 # 最大最小の差がb以下で、昇順に並べたときの値の間隔はa以上b以下 # 初項0として、最終項はa*(n-1)以上b以下。なのでa*(n-1)<=bでないなら0 # 初項0で末項がxとする。1回の操作ではA~Bを加算でき、n-1回の操作で合計xが加算された。 # A*(N-1)<=x<=B # <=> 初項0で末項がxとする。1回の操作では0~B-Aを加算でき、n-1回の操作で合計xが加算された。 # 0<=x<=B-A*(N-1) # i回目の操作でyiを加算する(0<=yi<=B-A) ... yi<=B-Aの条件はsum(yi)<=B-A*(N-1)の条件から自然と満たすので明示的に考える必要はない。 # x個のボールをn-1個のグループに分ける。 # <=> x個のボールを並べてn-2個区切りを入れる入れ方、cmb(x+1+n-2-1,n-2) # 区切り入る箇所がx+1,区切りの個数がn-2 def main1(n,m,a,b): if a*(n-1)>b:return 0 mod=998244353 def cmb(n,r,mod=mod): if (r<0 or r>n): return 0 r=min(r,n-r) return (g1[n]*g2[r]*g2[n-r])%mod g1=[1,1] # g1[i]=i! % mod :階乗 g2=[1,1] # g2[i]=(i!)^(-1) % mod :階乗の逆元 inverse=[0,1] for i in range(2,n+m+1): g1.append((g1[-1]*i)%mod) inverse.append((-inverse[mod%i]*(mod//i))%mod) g2.append((g2[-1]*inverse[-1])%mod) dp=[0]*(b-a*(n-1)+1) # dp[x]:初項0末項xとなる数列の個数。x個のボールをn-1個に分ける分け方。 # 横に並んだx個のボールがある。区切りを入れられる箇所がx+1個ある。重複を許しn-2個の区切りを入れる。 for x in range(b-a*(n-1)+1): dp[x]=cmb(x+1+n-2-1,n-2) sdp=[0] # sdp[x+1]:初項0末項x以下となる数列の個数 for x in dp:sdp.append(sdp[-1]+x) ans=0 for y in range(1,m-a*(n-1)+1): # 初項y 最小末項y+a*(n-1) 最大末項min(y+b,m) t=min(y+b,m) - (y+a*(n-1)) ans+=sdp[t+1] ans%=mod for i in range(1,n+1): ans=ans*i%mod return ans if __name__=='__main__': n,m,a,b=map(int,input().split()) ret1=main1(n,m,a,b) #ret0=main0(n,m,a,b) print(ret1) #print(ret0)