結果
問題 | No.2605 Pickup Parentheses |
ユーザー |
|
提出日時 | 2024-01-12 23:29:08 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 1,357 ms / 2,000 ms |
コード長 | 13,174 bytes |
コンパイル時間 | 380 ms |
コンパイル使用メモリ | 82,624 KB |
実行使用メモリ | 220,912 KB |
最終ジャッジ日時 | 2024-09-30 06:33:08 |
合計ジャッジ時間 | 47,345 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 68 |
ソースコード
import sys, time, randomfrom collections import deque, Counter, defaultdictinput = lambda: sys.stdin.readline().rstrip()ii = lambda: int(input())mi = lambda: map(int, input().split())li = lambda: list(mi())inf = 2 ** 63 - 1mod = 998244353class Calculator:def __init__(self):self.primitive=self.__primitive_root()self.__build_up()def __primitive_root(self):p=Modif p==2:return 1if p==998244353:return 3if p==10**9+7:return 5if p==163577857:return 23if p==167772161:return 3if p==469762049:return 3fac=[]q=2v=p-1while v>=q*q:e=0while v%q==0:e+=1v//=qif e>0:fac.append(q)q+=1if v>1:fac.append(v)g=2while g<p:if pow(g,p-1,p)!=1:return Noneflag=Truefor q in fac:if pow(g,(p-1)//q,p)==1:flag=Falsebreakif flag:return gg+=1#参考元: https://judge.yosupo.jp/submission/72676def __build_up(self):rank2=(~(Mod-1)&(Mod-2)).bit_length()root=[0]*(rank2+1); iroot=[0]*(rank2+1)rate2=[0]*max(0, rank2-1); irate2=[0]*max(0, rank2-1)rate3=[0]*max(0, rank2-2); irate3=[0]*max(0, rank2-2)root[-1]=pow(self.primitive, (Mod-1)>>rank2, Mod)iroot[-1]=pow(root[-1], Mod-2, Mod)for i in range(rank2)[::-1]:root[i]=root[i+1]*root[i+1]%Modiroot[i]=iroot[i+1]*iroot[i+1]%Modprod=iprod=1for i in range(rank2-1):rate2[i]=root[i+2]*prod%Modirate2[i]=iroot[i+2]*prod%Modprod*=iroot[i+2]; prod%=Modiprod*=root[i+2]; iprod%=Modprod=iprod = 1for i in range(rank2-2):rate3[i]=root[i + 3]*prod%Modirate3[i]=iroot[i + 3]*iprod%Modprod*=iroot[i + 3]; prod%=Modiprod*=root[i + 3]; iprod%=Modself.root=root; self.iroot=irootself.rate2=rate2; self.irate2=irate2self.rate3=rate3; self.irate3=irate3def Add(self, A, B):""" 必要ならば末尾に元を追加して, [A[i]+B[i]] を求める."""if type(A)==int:A=[A]if type(B)==int:B=[B]m=min(len(A), len(B))C=[(A[i]+B[i])%Mod for i in range(m)]C.extend(A[m:])C.extend(B[m:])return Cdef Sub(self, A, B):""" 必要ならば末尾に元を追加して, [A[i]-B[i]] を求める."""if type(A)==int:A=[A]if type(B)==int:B=[B]m=min(len(A), len(B))C=[0]*mC=[(A[i]-B[i])%Mod for i in range(m)]C.extend(A[m:])C.extend([-b%Mod for b in B[m:]])return Cdef Times(self,A, k):""" [k*A[i]] を求める."""return [k*a%Mod for a in A]#参考元 https://judge.yosupo.jp/submission/72676def NTT(self, A):""" A に Mod を法とする数論変換を施す※ Mod はグローバル変数から指定References:https://github.com/atcoder/ac-library/blob/master/atcoder/convolution.hpphttps://judge.yosupo.jp/submission/72676"""N=len(A)H=(N-1).bit_length()l=0I=self.root[2]rate2=self.rate2; rate3=self.rate3while l<H:if H-l==1:p=1<<(H-l-1)rot=1for s in range(1<<l):offset=s<<(H-l)for i in range(p):x=A[i+offset]; y=A[i+offset+p]*rot%ModA[i+offset]=(x+y)%ModA[i+offset+p]=(x-y)%Modif s+1!=1<<l:rot*=rate2[(~s&-~s).bit_length()-1]rot%=Modl+=1else:p=1<<(H-l-2)rot=1for s in range(1<<l):rot2=rot*rot%Modrot3=rot2*rot%Modoffset=s<<(H-l)for i in range(p):a0=A[i+offset]a1=A[i+offset+p]*rota2=A[i+offset+2*p]*rot2a3=A[i+offset+3*p]*rot3alpha=(a1-a3)%Mod*IA[i+offset]=(a0+a2+a1+a3)%ModA[i+offset+p]=(a0+a2-a1-a3)%ModA[i+offset+2*p]=(a0-a2+alpha)%ModA[i+offset+3*p]=(a0-a2-alpha)%Modif s+1!=1<<l:rot*=rate3[(~s&-~s).bit_length()-1]rot%=Modl+=2#参考元 https://judge.yosupo.jp/submission/72676def Inverse_NTT(self, A):""" A を Mod を法とする逆数論変換を施す※ Mod はグローバル変数から指定References:https://github.com/atcoder/ac-library/blob/master/atcoder/convolution.hpphttps://judge.yosupo.jp/submission/72676"""N=len(A)H=(N-1).bit_length()l=HJ=self.iroot[2]irate2=self.rate2; irate3=self.irate3while l:if l==1:p=1<<(H-l)irot=1for s in range(1<<(l-1)):offset=s<<(H-l+1)for i in range(p):x=A[i+offset]; y=A[i+offset+p]A[i+offset]=(x+y)%ModA[i+offset+p]=(x-y)*irot%Modif s+1!=1<<(l-1):irot*=irate2[(~s&-~s).bit_length()-1]irot%=Modl-=1else:p=1<<(H-l)irot=1for s in range(1<<(l-2)):irot2=irot*irot%Modirot3=irot2*irot%Modoffset=s<<(H-l+2)for i in range(p):a0=A[i+offset]a1=A[i+offset+p]a2=A[i+offset+2*p]a3=A[i+offset+3*p]beta=(a2-a3)*J%ModA[i+offset]=(a0+a1+a2+a3)%ModA[i+offset+p]=(a0-a1+beta)*irot%ModA[i+offset+2*p]=(a0+a1-a2-a3)*irot2%ModA[i+offset+3*p]=(a0-a1-beta)*irot3%Modif s+1!=1<<(l-2):irot*=irate3[(~s&-~s).bit_length()-1]irot%=Modl-=2N_inv=pow(N,Mod-2,Mod)for i in range(N):A[i]=N_inv*A[i]%Moddef non_zero_count(self, A):""" A にある非零の数を求める. """return len(A)-A.count(0)def is_sparse(self, A, K=None):""" A が疎かどうかを判定する. """if K==None:K=25return self.non_zero_count(A)<=Kdef coefficients_list(self, A):""" A にある非零のリストを求める.output: ( [d[0], ..., d[k-1] ], [f[0], ..., f[k-1] ]) : a[d[j]]=f[j] であることを表している."""f=[]; d=[]for i in range(len(A)):if A[i]:d.append(i)f.append(A[i])return d,fdef Convolution(self, A, B):""" A, B で Mod を法とする畳み込みを求める.※ Mod はグローバル変数から指定"""if not A or not B:return []N=len(A)M=len(B)L=M+N-1if min(N,M)<=50:if N<M:N,M=M,NA,B=B,AC=[0]*Lfor i in range(N):for j in range(M):C[i+j]+=A[i]*B[j]C[i+j]%=Modreturn CH=L.bit_length()K=1<<HA=A+[0]*(K-N)B=B+[0]*(K-M)self.NTT(A)self.NTT(B)for i in range(K):A[i]=A[i]*B[i]%Modself.Inverse_NTT(A)return A[:L]def Autocorrelation(self, A):""" A 自身に対して,Mod を法とする畳み込みを求める.※ Mod はグローバル変数から指定"""N=len(A)L=2*N-1if N<=50:C=[0]*Lfor i in range(N):for j in range(N):C[i+j]+=A[i]*A[j]C[i+j]%=Modreturn CH=L.bit_length()K=1<<HA=A+[0]*(K-N)self.NTT(A)for i in range(K):A[i]=A[i]*A[i]%Modself.Inverse_NTT(A)return A[:L]def Multiple_Convolution(self, *A):""" A=(A[0], A[1], ..., A[d-1]) で Mod を法とする畳み込みを行う."""from collections import dequeif not A:return [1]Q=deque(list(range(len(A))))A=list(A)while len(Q)>=2:i=Q.popleft(); j=Q.popleft()A[i]=self.Convolution(A[i], A[j])Q.append(i)i=Q.popleft()return A[i]def Inverse(self, F, length=None):if length==None:M=len(F)else:M=lengthif M<=0:return []if self.is_sparse(F):"""愚直に漸化式を用いて求める.計算量: F にある係数が非零の項の個数を K, 求める最大次数を N として, O(NK) 時間"""d,f=self.coefficients_list(F)G=[0]*Malpha=pow(F[0], Mod-2, Mod)G[0]=alphafor i in range(1, M):for j in range(1, len(d)):if d[j]<=i:G[i]+=f[j]*G[i-d[j]]%Modelse:breakG[i]%=ModG[i]=(-alpha*G[i])%Moddel G[M:]else:"""FFTの理論を応用して求める.計算量: 求めたい項の個数をNとして, O(N log N)Reference: https://judge.yosupo.jp/submission/42413"""N=len(F)r=pow(F[0],Mod-2,Mod)m=1G=[r]while m<M:A=F[:min(N, 2*m)]; A+=[0]*(2*m-len(A))B=G.copy(); B+=[0]*(2*m-len(B))Calc.NTT(A); Calc.NTT(B)for i in range(2*m):A[i]=A[i]*B[i]%ModCalc.Inverse_NTT(A)A=A[m:]+[0]*mCalc.NTT(A)for i in range(2*m):A[i]=-A[i]*B[i]%ModCalc.Inverse_NTT(A)G.extend(A[:m])m<<=1G=G[:M]return Gdef Floor_Div(self, F, G):assert F[-1]assert G[-1]F_deg=len(F)-1G_deg=len(G)-1if F_deg<G_deg:return []m=F_deg-G_deg+1return self.Convolution(F[::-1], Calc.Inverse(G[::-1],m))[m-1::-1]def Mod(self, F, G):while F and F[-1]==0:F.pop()while G and G[-1]==0:G.pop()if not F:return []return Calc.Sub(F, Calc.Convolution(Calc.Floor_Div(F,G),G))class Combinatorics():def __init__(self, mod, maxi):self.mod = modself.maxi = maxiself.facs = [1] * (maxi + 1)self.factinvs = [1] * (maxi + 1)self.invs = [1] * (maxi + 1)for i in range(2, self.maxi + 1):self.facs[i] = ((self.facs[i-1] * i) % self.mod)self.invs[i] = (-self.invs[self.mod % i] * (self.mod // i)) % self.modself.factinvs[i] = (self.factinvs[i-1] * self.invs[i]) % self.moddef choose(self, n, k):if k < 0 or k > n: return 0if k == 0 or k == n: return 1k = min(k, n - k)return (((self.facs[n] * self.factinvs[k]) % self.mod) * self.factinvs[n-k]) % self.moddef perm(self, n, k):return (self.choose(n, k) * self.facs[k]) % self.moddef homop(self, n, k):if n == k == 0:return 1return self.choose(n + k - 1, k)Mod = modCalc = Calculator()n, m = mi()C = Combinatorics(mod, 25* 10 ** 5 + 2)a = []for _ in range(m):l, r = mi()a.append(r - l + 1)A = []cat = [0] * (2 * n + 3)for i in range(1, n + 1):cat[2 * i] = C.choose(2 * i, i) * pow(i + 1, -1, mod) % modfor v in a:now = [0] * (v + 1)now[0] = 1now[v] = -cat[v]A.append(now)C = Calc.Multiple_Convolution(*A)C += [0] * (n + 1 - len(C))ans = 0cat[0] = 1for i in range(n + 1):ans += C[i] * cat[n - i] % modans %= modprint(ans)