洛谷P4389:付公主的背包(多项式、生成函数)
對于一些生成函數(shù)累乘的題目,也許可以通過求 ln?\lnln 轉(zhuǎn)化為累加問題從而完成簡化。
解析
不難寫出對于單個物品 kkk 的生成函數(shù):
∑i=1xVi=11?xVK\sum_{i=1}x^{Vi}=\frac{1}{1-x^{V_K}}i=1∑?xVi=1?xVK?1?
那么答案的生成函數(shù)就是所有物品的函數(shù)的卷積:
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∏n?1?xVK?1?=∏k?(1?xVK?)1?
那么我們只需要求出分母上的累乘最后求一下逆即可。
暴力累乘復(fù)雜度是 O(nmlog?m)O(nm\log m)O(nmlogm) 的,無法通過。
考慮轉(zhuǎn)化為 ln?\lnln。
(為了簡潔,下面考慮單獨(dú)一個物品,省略角標(biāo) kkk)
一個常見的套路:先求導(dǎo)再積分:
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?
做一個桶統(tǒng)計每個容量物品有多少個,用類似埃氏篩的方式在對應(yīng)的位置把系數(shù)加上即可。
得到這個函數(shù)后,我們 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 */總結(jié)
以上是生活随笔為你收集整理的洛谷P4389:付公主的背包(多项式、生成函数)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑如何设置自动关机 电脑设置自动关机的
- 下一篇: 手机怎么关闭自动清除缓存(手机怎么关闭自