[LOJ2541][PKUWC2018]猎人杀(容斥+分治+FFT)
https://blog.csdn.net/Maxwei_wzj/article/details/80714129
n个二项式相乘可以用分治+FFT的方法,使用空间回收可以只开log个数组。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=300010,mod=998244353; 7 int n,top,ans,w[N],a[N],rev[N],S[51],tmp[51][N]; 8 9 int ksm(int a,int b){ 10 int res=1; 11 for (; b; a=1ll*a*a%mod,b>>=1) 12 if (b & 1) res=1ll*res*a%mod; 13 return res; 14 } 15 16 void NTT(int a[],int len,int f){ 17 int n=1,L=0; 18 for (; n<len; n<<=1) L++; 19 for (int i=0; i<n; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); 20 for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i],a[rev[i]]); 21 for (int i=1; i<n; i<<=1){ 22 int wn=ksm(3,(f==1) ? (mod-1)/(i<<1) : (mod-1)-(mod-1)/(i<<1)); 23 for (int p=i<<1,j=0; j<n; j+=p){ 24 int w=1; 25 for (int k=0; k<i; k++,w=1ll*w*wn%mod){ 26 int x=a[j+k],y=1ll*w*a[i+j+k]%mod; 27 a[j+k]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod; 28 } 29 } 30 } 31 if (f==1) return; 32 int inv=ksm(n,mod-2); 33 for (int i=0; i<n; i++) a[i]=1ll*a[i]*inv%mod; 34 } 35 36 int solve(int l,int r,int a[]){ 37 if (l==r){ a[0]=1; a[w[l]]=mod-1; return w[l]; } 38 int mid=(l+r)>>1,l1,l2,ls,rs,n; 39 ls=S[top--]; l1=solve(l,mid,tmp[ls]); 40 rs=S[top--]; l2=solve(mid+1,r,tmp[rs]); 41 for (n=1; n<=l1+l2; n<<=1); 42 NTT(tmp[ls],n,1); NTT(tmp[rs],n,1); 43 for (int i=0; i<n; i++) a[i]=1ll*tmp[ls][i]*tmp[rs][i]%mod; 44 NTT(a,n,-1); S[++top]=ls; S[++top]=rs; 45 for (int i=0; i<n; i++) tmp[ls][i]=tmp[rs][i]=0; 46 return l1+l2; 47 } 48 49 int main(){ 50 freopen("kill.in","r",stdin); 51 freopen("kill.out","w",stdout); 52 scanf("%d",&n); 53 rep(i,1,n) scanf("%d",&w[i]); 54 rep(i,1,49) S[++top]=i; 55 int len=solve(2,n,a); 56 rep(i,0,len) ans=(ans+1ll*a[i]*ksm(w[1]+i,mod-2))%mod; 57 printf("%lld\n",1ll*ans*w[1]%mod); 58 return 0; 59 }