problem
这就是一道普通的背包问题。
给定一个容量为 1 0 5 10^5 105 的背包,有 n n n 种商品,商品体积为 v i v_i vi,每个都有 1 0 5 10^5 105 件。
给定 m m m,对于 ∀ s ∈ [ 1 , m ] \forall s\in [1,m] ∀s∈[1,m],请求出用这些商品恰好装 s s s 体积的方案数。
答案对 998244353 998244353 998244353 取模。
数据范围: v i ≤ n , m ≤ 1 0 5 v_i\le n,m\le10^5 vi≤n,m≤105。
solution
首先,每个物品可以看做有无限个,因为 m m m 最大也才 1 0 5 10^5 105。
对于第 k k k 个物品( k ∈ [ 1 , n ] k\in[1,n] k∈[1,n]),把它的生成函数写出来:
F k ( x ) = ∑ i = 0 ∞ x i × v k = 1 1 − x v k F_k(x)=\sum_{i=0}^{\infty}x^{i\times v_k}=\frac{1}{1-x^{v_k}} Fk(x)=i=0∑∞xi×vk=1−xvk1
那么,我们现在的任务就是,把这 n n n 个生成函数卷起来,然后求每一项的系数。
有一个想法是先对所以函数取 ln \ln ln,再加起来,最后用 exp 还原出答案。
设 G k ( x ) = ln F k ( x ) G_k(x)=\ln F_k(x) Gk(x)=lnFk(x),考虑先对 G k ( x ) G_k(x) Gk(x) 求导,得到:
G k ′ ( x ) = F k ′ ( x ) F k ( x ) = ( 1 − x v k ) ∑ i = 0 ∞ ( i × v k ) x i × v k − 1 = ∑ i = 0 ∞ ( i × v k ) x i × v k − 1 − ∑ i = 0 ∞ ( i × v k ) x ( i + 1 ) × v k − 1 = ∑ i = 0 ∞ v k x i × v k − 1 \begin{aligned} G_k'(x)&=\frac{F_k'(x)}{F_k(x)}\\ &=(1-x^{v_k})\sum_{i=0}^{\infty}(i\times v_k)x^{i\times v_k-1}\\ &=\sum_{i=0}^{\infty}(i\times v_k)x^{i\times v_k-1}-\sum_{i=0}^{\infty}(i\times v_k)x^{(i+1)\times v_k-1}\\ &=\sum_{i=0}^{\infty}v_kx^{i\times v_k-1} \end{aligned} Gk′(x)=Fk(x)Fk′(x)=(1−xvk)i=0∑∞(i×vk)xi×vk−1=i=0∑∞(i×vk)xi×vk−1−i=0∑∞(i×vk)x(i+1)×vk−1=i=0∑∞vkxi×vk−1
然后考虑把 G k ( x ) G_k(x) Gk(x) 用积分积回去,得到:
G k ( x ) = ∫ G k ′ ( x ) = ∑ i = 1 ∞ v k i × v k x i × v k = ∑ i = 1 ∞ 1 i x i × v k \begin{aligned} G_k(x)&=\int G'_{k}(x)\\ &=\sum_{i=1}^{\infty}\frac{v_k}{i\times v_k}x^{i\times v_k}\\ &=\sum_{i=1}^{\infty}\frac 1 ix^{i\times v_k} \end{aligned} Gk(x)=∫Gk′(x)=i=1∑∞i×vkvkxi×vk=i=1∑∞i1xi×vk
那么我们可以枚举体积,然后在倍数的地方加上相应的贡献,这部分复杂度 O ( n log n ) O(n\log n) O(nlogn)。
然后最后的多项式 exp 复杂度也是 O ( n log n ) O(n\log n) O(nlogn) 的。
code
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define N 500005
#define P 998244353
using namespace std;
const int g=3;
typedef vector<int> poly;
int n,m,pos[N],v[N],inv[N];
int add(int x,int y) {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y) {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y) {return 1ll*x*y%P;}
int power(int a,int b,int ans=1){
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans=mul(ans,a);
return ans;
}
int *w[21],C=20;
void init_w(){
for(int i=1;i<=C;++i)
w[i]=new int[1<<(i-1)];
int now=power(g,(P-1)/(1<<C));
w[C][0]=1;
for(int i=1;i<(1<<(C-1));++i) w[C][i]=mul(w[C][i-1],now);
for(int i=C-1;i;--i)
for(int j=0;j<(1<<(i-1));++j)
w[i][j]=w[i+1][j<<1];
}
void init_inv(){
inv[1]=1;
for(int i=2;i<N;++i) inv[i]=mul(P-P/i,inv[P%i]);
}
void init_pos(int lim){
for(int i=0;i<lim;++i)
pos[i]=(pos[i>>1]>>1)|((i&1)*(lim>>1));
}
void NTT(poly &f,int lim,int type){
for(int i=0;i<lim;++i)
if(pos[i]>i) swap(f[i],f[pos[i]]);
for(int mid=1,l=1;mid<lim;mid<<=1,++l){
for(int i=0;i<lim;i+=(mid<<1)){
for(int j=0;j<mid;++j){
int p0=f[i+j],p1=mul(f[i+j+mid],w[l][j]);
f[i+j]=add(p0,p1),f[i+j+mid]=dec(p0,p1);
}
}
}
if(type==-1&&(reverse(f.begin()+1,f.begin()+lim),1)){
int inv=power(lim,P-2);
for(int i=0;i<lim;++i) f[i]=mul(f[i],inv);
}
}
poly operator*(poly A,poly B){
int lim=1,len=A.size()+B.size()-2;
while(lim<=len) lim<<=1;init_pos(lim);
A.resize(lim),NTT(A,lim,1);
B.resize(lim),NTT(B,lim,1);
for(int i=0;i<lim;++i) A[i]=mul(A[i],B[i]);
NTT(A,lim,-1),A.resize(len+1);
return A;
}
poly Inv(poly A,int len){
poly C,B(1,power(A[0],P-2));
for(int lim=4;lim<(len<<2);lim<<=1){
init_pos(lim);
C=A,C.resize(lim>>1);
C.resize(lim),NTT(C,lim,1);
B.resize(lim),NTT(B,lim,1);
for(int i=0;i<lim;++i) B[i]=mul(B[i],dec(2,mul(B[i],C[i])));
NTT(B,lim,-1),B.resize(lim>>1);
}
B.resize(len);return B;
}
poly Deriv(poly A){
for(int i=0;i<A.size()-1;++i) A[i]=mul(A[i+1],i+1);
A.pop_back();return A;
}
poly Integ(poly A){
A.push_back(0);
for(int i=A.size()-1;i;--i) A[i]=mul(A[i-1],inv[i]);
A[0]=0;return A;
}
poly Ln(poly A,int len){
A=Integ(Deriv(A)*Inv(A,len)),A.resize(len);
return A;
}
poly Exp(poly A,int len){
poly B(1,1),C;A.resize(len<<1);
for(int lim=2;lim<(len<<1);lim<<=1){
C=Ln(B,lim);
for(int i=0;i<lim;++i) C[i]=dec(A[i],C[i]);
C[0]=add(C[0],1),B=B*C,B.resize(lim);
}
B.resize(len);return B;
}
int main(){
scanf("%d%d",&n,&m),init_w(),init_inv();
for(int i=1,x;i<=n;++i) scanf("%d",&x),v[x]++;
poly f(m+1,0);
for(int i=1;i<=m;++i){
for(int j=1;i*j<=m;++j){
f[i*j]=add(f[i*j],mul(v[i],inv[j]));
}
}
f=Exp(f,m+1);
for(int i=1;i<=m;++i) printf("%d\n",f[i]);
return 0;
}