1. 程式人生 > >[luogu4389]付公主的背包(FFT)

[luogu4389]付公主的背包(FFT)

put code pro 背包 space stdin size 計數問題 pen

完全背包方案計數問題的FFT優化。
首先寫成生成函數的形式:對重量為V的背包,它的生成函數為$\sum\limits_{i=0}^{+\infty}x^{Vi}=\frac{1}{1-x^{V}}$
於是答案就是$\prod \frac{1}{1-x^{V_k}}$。
直接做顯然會超時,考慮使用ln將乘法變為加法。
https://www.cnblogs.com/cjyyb/p/10132855.html

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5
#define mem(a) memset(a,0,sizeof(a)) 6 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 7 using namespace std; 8 9 const int N=500010,mod=998244353,inv2=(mod+1)/2; 10 int n,m,v,cnt[N],rev[N],inv[N],X[N],Y[N],A[N],D[N],E[N],F[N]; 11 12 void Print(int a[],int n=::n){ for (int i=0; i<n; i++) printf("
%d ",a[i]); puts(""); } 13 14 int ksm(int a,int b){ 15 int res=1; 16 for (; b; a=1ll*a*a%mod,b>>=1) 17 if (b & 1) res=1ll*res*a%mod; 18 return res; 19 } 20 21 void NTT(int a[],int n,bool f){ 22 for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
23 for (int i=1; i<n; i<<=1){ 24 int wn=ksm(3,f ? (mod-1)/(i<<1) : (mod-1)-(mod-1)/(i<<1)); 25 for (int p=i<<1,j=0; j<n; j+=p){ 26 int w=1; 27 for (int k=0; k<i; k++,w=1ll*w*wn%mod){ 28 int x=a[j+k],y=1ll*w*a[i+j+k]%mod; 29 a[j+k]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod; 30 } 31 } 32 } 33 if (f) return; 34 int inv=ksm(n,mod-2); 35 for (int i=0; i<n; i++) a[i]=1ll*a[i]*inv%mod; 36 } 37 38 void mul(int a[],int b[],int l){ 39 int n=1,L=0; 40 for (; n<(l<<1); n<<=1) L++; 41 for (int i=0; i<n; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); 42 NTT(a,n,1); NTT(b,n,1); 43 for (int i=0; i<n; i++) a[i]=1ll*a[i]*b[i]%mod; 44 NTT(a,n,0); NTT(b,n,0); 45 } 46 47 void Inv(int a[],int b[],int l){ 48 if (l==1){ b[0]=ksm(a[0],mod-2); return; } 49 Inv(a,b,l>>1); int n=1,L=0; 50 for (; n<(l<<1); n<<=1) L++; 51 for (int i=0; i<n; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); 52 for (int i=0; i<l; i++) A[i]=a[i]; 53 NTT(A,n,1); NTT(b,n,1); 54 for (int i=0; i<n; i++) b[i]=1ll*b[i]*(2-1ll*A[i]*b[i]%mod+mod)%mod; 55 NTT(b,n,0); 56 for (int i=l; i<n; i++) b[i]=0; 57 for (int i=0; i<n; i++) A[i]=0; 58 } 59 60 void Deri(int a[],int b[],int l){ 61 for (int i=1; i<l; i++) b[i-1]=1ll*i*a[i]%mod; 62 } 63 64 void Inte(int a[],int b[],int l){ 65 for (int i=1; i<l; i++) b[i]=1ll*a[i-1]*inv[i]%mod; b[0]=0; 66 } 67 68 void Ln(int a[],int b[],int l){ 69 Deri(a,D,l); Inv(a,E,l); mul(D,E,l); Inte(D,b,l); 70 for (int i=0; i<(l<<1); i++) D[i]=E[i]=0; 71 } 72 73 void Exp(int a[],int b[],int l){ 74 if (l==1){ b[0]=1; return; } 75 Exp(a,b,l>>1); Ln(b,F,l); int n=1,L=0; 76 for (; n<(l<<1); n<<=1) L++; 77 for (int i=0; i<n; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); 78 for (int i=0; i<l; i++) F[i]=(-F[i]+a[i]+mod)%mod; F[0]=(F[0]+1)%mod; 79 NTT(F,n,1); NTT(b,n,1); 80 for (int i=0; i<n; i++) b[i]=1ll*b[i]*F[i]%mod; 81 NTT(b,n,0); 82 for (int i=l; i<n; i++) b[i]=0; 83 for (int i=0; i<n; i++) F[i]=0; 84 } 85 86 int main(){ 87 freopen("4389.in","r",stdin); 88 freopen("4389.out","w",stdout); 89 scanf("%d%d",&n,&m); 90 int l=1; for (; l<=m; l<<=1); inv[0]=inv[1]=1; 91 rep(i,2,l) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; 92 rep(i,1,n) scanf("%d",&v),cnt[v]++; 93 rep(i,1,m) if (cnt[i]) for (int j=1; j*i<=m; j++) X[j*i]=(X[j*i]+1ll*cnt[i]*inv[j])%mod; 94 Exp(X,Y,l); 95 rep(i,1,m) printf("%d\n",Y[i]); 96 return 0; 97 }

[luogu4389]付公主的背包(FFT)