#4155. 咱们去烧菜吧
题意
内存限制:512 MiB
时间限制:1000 ms
你有 $m$ 种物品,第 $i$ 种物品的大小为 $a_i$,数量为 $b_i$($b_i=0$ 表示有无限个)。
你还有 $n$ 个背包,体积分别为 $1$ 到 $n$,现在你很想知道用这些物品填满某个背包的方案数。
为了满足你的好奇心,你决定把填满每个背包的方案数都算一遍。
因为你其实只是闲得无聊,所以你只想知道方案数对 $998244353$($7\times 17\times 2^{23}+1$,一个质数)取模后的值。
$0< n,m\le 10^5, 0\le a_i\le 110000,0\le b_i\le 10^6$。
题解
把第 $i$ 个物品的生成函数写出,设 $b_i>0$,即 $F_i(x)=\sum_{j=0}^{b_i} x^{a_i \times j}=\frac{1-x^{a_i \times (b_i+1)}}{1-x^{a_i}}$
那么当 $b_i=0$ 时, $F_i(x)=\sum_{j=0}^{\infty} x^{a_i \times j}=\frac{1}{1-x^{a_i}}$
则最后的答案的生成函数 $G(x)=\prod_{i=1}^nF_i(x)$
两边取对数,即 $\ln G(x)=\ln (\prod_{i=1}^nF_i(x))=\sum_{i=1}^n \ln F_i(x)=\sum_{i=1}^n(\ln (1-x^{a_i \times (b_i+1)})-\ln(1-x^{a_i}))$
又知道 $\ln(1-x^k)=\sum_{i=1}^{\infty} \frac{x^{i \times k}}{i}$
所以对于每个 $k$ ,都会对 $x^{i \times k}$ 的系数造成影响,所以这一部分可以 $O(n\ln n)$ 预处理
所以最后做个多项式 $exp$ 即可
代码
#include <bits/stdc++.h> #define I inline using namespace std; const int P=998244353,N=5e5+5; int n,m,a[N],b[N],r[N],t,p,G[2]={3,332748118}; int A[N],B[N],C[N],D[N],E[N],F[N],jc[N],ny[N]; I int X(int x){if (x>=P) x-=P;return x;} I int inv(int x){return 1ll*jc[x-1]*ny[x]%P;} I int K(int x,int y){ int A=1; for (;y;y>>=1,x=1ll*x*x%P) if (y&1) A=1ll*A*x%P; return A; } I void Ntt(int *g,bool o){ for (int i=0;i<t;i++) if (i<r[i]) swap(g[i],g[r[i]]); for (int wn,i=1;i<t;i<<=1){ wn=K(G[o],(P-1)/(i<<1)); for (int x,y,j=0;j<t;j+=(i<<1)) for (int w=1,k=0;k<i;k++,w=1ll*w*wn%P) x=g[j+k],y=1ll*w*g[i+j+k]%P, g[j+k]=X(x+y),g[i+j+k]=X(x-y+P); } if (o) for (int i=0,v=K(t,P-2);i<t;i++) g[i]=1ll*v*g[i]%P; } I void dao(int *a,int *b,int l){ for (int i=1;i<l;i++) b[i-1]=1ll*i*a[i]%P; b[l]=b[l-1]=0; } I void jifen(int *a,int *b,int l){ for (int i=1;i<l;i++) b[i]=1ll*a[i-1]*inv(i)%P; b[0]=0; } I void pre(int l){ for (t=1,p=0;t<l+l;t<<=1,p++); for (int i=0;i<t;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(p-1)); } I void getinv(int *a,int *b,int l){ if (l==1){ b[0]=K(a[0],P-2);return; } getinv(a,b,(l+1)>>1); for (int i=0;i<l;i++) A[i]=a[i],B[i]=b[i]; pre(l);Ntt(A,0);Ntt(B,0); for (int i=0;i<t;i++) A[i]=1ll*A[i]*B[i]%P*B[i]%P; Ntt(A,1);for (int i=0;i<l;i++) b[i]=X(X(b[i]+b[i])-A[i]+P); for (int i=0;i<t;i++) A[i]=B[i]=0; } I void getln(int *a,int *b,int l){ dao(a,C,l);getinv(a,D,l); pre(l);Ntt(C,0);Ntt(D,0); for (int i=0;i<t;i++) C[i]=1ll*C[i]*D[i]%P; Ntt(C,1);jifen(C,b,l); for (int i=0;i<t;i++) C[i]=D[i]=0; } I void getexp(int *a,int *b,int l){ if (l==1){b[0]=1;return;} getexp(a,b,(l+1)>>1); for (int i=0;i<l;i++) E[i]=b[i]; getln(b,F,l); for (int i=0;i<l;i++) F[i]=X(a[i]-F[i]+P); F[0]=X(F[0]+1);pre(l); Ntt(F,0);Ntt(E,0); for (int i=0;i<t;i++) E[i]=1ll*E[i]*F[i]%P; Ntt(E,1); for (int i=0;i<l;i++) b[i]=E[i]; for (int i=0;i<t;i++) E[i]=F[i]=0; } int main(){ scanf("%d%d",&n,&m); for (int x,y,i=1;i<=m;i++){ scanf("%d%d",&x,&y); if (x<=n) a[x]++; if (y && 1ll*x*(y+1)<=1ll*n) a[x*(y+1)]--; } jc[0]=1; for (int i=1;i<=n;i++) jc[i]=1ll*i*jc[i-1]%P; ny[n]=K(jc[n],P-2); for (int i=n;i;i--) ny[i-1]=1ll*i*ny[i]%P; for (int i=1;i<=n;i++){ if (!a[i]) continue; if (a[i]<0) a[i]+=P; for (int j=1;j*i<=n;j++) b[i*j]=X(b[i*j]+1ll*a[i]*inv(j)%P); a[i]=0; } getexp(b,a,n+1); for (int i=1;i<=n;i++) printf("%d\n",a[i]); return 0; }