对于一些生成函数累乘的题目,也许可以通过求 ln\lnln 转化为累加问题从而完成简化。
解析
不难写出对于单个物品 kkk 的生成函数:
∑i=1xVi=11−xVK\sum_{i=1}x^{Vi}=\frac{1}{1-x^{V_K}}i=1∑xVi=1−xVK1
那么答案的生成函数就是所有物品的函数的卷积:
F(x)=∏k=1n11−xVK=1∏k(1−xVK)F(x)=\prod_{k=1}^n\frac{1}{1-x^{V_K}}=\frac{1}{\prod_{k}(1-x^{V_K})}F(x)=k=1∏n1−xVK1=∏k(1−xVK)1
那么我们只需要求出分母上的累乘最后求一下逆即可。
暴力累乘复杂度是 O(nmlogm)O(nm\log m)O(nmlogm) 的,无法通过。
考虑转化为 ln\lnln。
(为了简洁,下面考虑单独一个物品,省略角标 kkk)
一个常见的套路:先求导再积分:
f(x)=ln(1−xV)f(x)=\ln(1-x^V)f(x)=ln(1−xV)
f′(x)=−VxV−111−xV=−VxV−1∑i=0xVi=−∑i=0VxVi+V−1f'(x)=-Vx^{V-1}\frac{1}{1-x^V}=-Vx^{V-1}\sum_{i=0}x^{Vi}=-\sum_{i=0}Vx^{Vi+V-1}f′(x)=−VxV−11−xV1=−VxV−1i=0∑xVi=−i=0∑VxVi+V−1
f(x)=−∑i=0VxVi+VVi+V=−∑i=1xViif(x)=-\sum_{i=0}\frac{Vx^{Vi+V}}{Vi+V}=-\sum_{i=1}\frac{x^{Vi}}{i}f(x)=−i=0∑Vi+VVxVi+V=−i=1∑ixVi
做一个桶统计每个容量物品有多少个,用类似埃氏筛的方式在对应的位置把系数加上即可。
得到这个函数后,我们 exp\expexp 回去再求逆就完成了本题。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
const int N=4e5+100;
const int mod=998244353;
int n,m,k;
inline ll ksm(ll x,ll k){ll res=1;while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}
int r[N];
void init(int n,int &lim){lim=1;int L=0;while(lim<n) lim<<=1,L++;for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
}
void NTT(ll *x,int lim,int op){for(int i=0;i<lim;i++) if(i<r[i]) swap(x[i],x[r[i]]);for(int l=1;l<lim;l<<=1){ll w=ksm(3,(mod-1)/(l<<1));if(op==-1) w=ksm(w,mod-2);for(int st=0;st<lim;st+=(l<<1)){for(ll i=0,now=1;i<l;i++,now=now*w%mod){ll u=x[st+i],v=now*x[st+i+l]%mod;x[st+i]=u+v>=mod?u+v-mod:u+v;x[st+i+l]=u-v<0?u-v+mod:u-v;}}}if(op==-1){ll ni=ksm(lim,mod-2);for(int i=0;i<lim;i++) x[i]=x[i]*ni%mod;}return;
}
void copy(ll *a,ll *b,int n,int lim){assert(n<=lim);memcpy(a,b,sizeof(ll)*n);fill(a+n,a+lim,0);return;
}
void mul(ll *a,ll *b,ll *c,int n,int m){static ll u[N],v[N];static int lim;init(n+m-1,lim);copy(u,a,n,lim);copy(v,b,m,lim);NTT(u,lim,1);NTT(v,lim,1);for(int i=0;i<lim;i++) c[i]=u[i]*v[i]%mod;NTT(c,lim,-1);return;
}
void inv(ll *h,ll *f,int n){static ll t1[N],t2[N];static int lim;if(n==1){f[0]=ksm(h[0],mod-2);return;}inv(h,f,(n+1)>>1);init(n<<1,lim);fill(f+((n+1)>>1),f+lim,0);copy(t1,f,n,lim);copy(t2,h,n,lim);NTT(t1,lim,1);NTT(t2,lim,1);for(int i=0;i<lim;i++) t1[i]=(2*t1[i]-t1[i]*t1[i]%mod*t2[i]%mod+mod)%mod;NTT(t1,lim,-1);memcpy(f,t1,sizeof(ll)*n);return;
}
//499122177
void Sqrt(ll *h,ll *f,int n){static ll t1[N],t2[N];static int lim;if(n==1){f[0]=1;return;}Sqrt(h,f,(n+1)>>1);init(n<<1,lim);fill(f+((n+1)>>1),f+lim,0);inv(f,t1,n);fill(t1+n,t1+lim,0);mul(h,t1,t1,n,n);copy(t2,f,n,lim);NTT(t1,lim,1);NTT(t2,lim,1);for(int i=0;i<lim;i++) t1[i]=(t1[i]+t2[i]%mod)*499122177%mod;NTT(t1,lim,-1);memcpy(f,t1,sizeof(ll)*n);return;
}
void dao(ll *h,ll *f,int n){static ll t[N];static int lim;init(n<<1,lim);copy(t,h,n,lim);f[n-1]=0;for(int i=0;i<n-1;i++) f[i]=t[i+1]*(i+1)%mod;fill(f+n,f+lim,0);return;
}
void jifen(ll *h,ll *f,int n){static ll t[N];static int lim;init(n<<1,lim);copy(t,h,n,lim);f[0]=0;for(int i=1;i<n;i++) f[i]=h[i-1]*ksm(i,mod-2)%mod;fill(f+n,f+lim,0);
}
void Ln(ll *h,ll *f,int n){static ll t1[N],t2[N];static int lim;init(n<<1,lim);inv(h,t1,n);fill(t1+n,t1+lim,0);dao(h,t2,n);mul(t1,t2,t1,n,n);jifen(t1,f,n);return;
}
void Exp(ll *h,ll *f,int n){static ll t1[N],t2[N],t3[N];static int lim;if(n==1){f[0]=1;return;}Exp(h,f,(n+1)>>1);init(n<<1,lim);fill(f+((n+1)>>1),f+lim,0);copy(t1,f,n,lim);copy(t2,h,n,lim);Ln(f,t3,n);fill(t3+n,t3+lim,0);NTT(t1,lim,1);NTT(t2,lim,1);NTT(t3,lim,1);for(int i=0;i<lim;i++) t1[i]=t1[i]*(1+t2[i]-t3[i]+mod)%mod;NTT(t1,lim,-1);memcpy(f,t1,sizeof(ll)*n);return;
}
int bac[N];
ll a[N],b[N],c[N];
ll jc[N],ni[N];
void calc(){jc[0]=1;for(int i=1;i<=m;i++) jc[i]=jc[i-1]*i%mod;ni[m]=ksm(jc[m],mod-2);for(int i=m-1;i>=0;i--) ni[i]=ni[i+1]*(i+1)%mod;for(int i=m;i>=1;i--) ni[i]=ni[i]*jc[i-1]%mod;return;
}
signed main() {
#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);
#endifn=read();m=read();calc();for(int i=1;i<=n;i++) bac[read()]++;for(int i=1;i<=m;i++){if(bac[i]) for(int j=i;j<=m;j+=i){ a[j]=(a[j]+mod-bac[i]*ni[j/i]%mod)%mod;//printf("i=%d j=%d =%lld\n",i,j,a[j]);}}++m;//for(int i=0;i<m;i++) printf("%lld ",a[i]);putchar('\n');Exp(a,b,m);inv(b,c,m);for(int i=1;i<m;i++) printf("%lld\n",c[i]);return 0;
}
/*
4
0 1 1
*/