P4389-付公主的背包【生成函数,多项式exp】
正題
題目鏈接:https://www.luogu.com.cn/problem/P4389
題目大意
nnn種物品,第iii種大小為viv_ivi?,數(shù)量無限。對于每個s∈[1,m]s\in[1,m]s∈[1,m]求剛好填滿sss容量的方案數(shù)。
1≤n,m≤1051\leq n,m\leq 10^51≤n,m≤105
解題思路
統(tǒng)計和為一定值的方案數(shù),好像可以生成函數(shù)做?
每種物品大小vvv有一個生成函數(shù)
F(x)=∑i≥0xi×v=11?xvF(x)=\sum_{i\geq 0}x^{i\times v}=\frac{1}{1-x^v}F(x)=i≥0∑?xi×v=1?xv1?
然后所有生成函數(shù)乘起來就好了,但這樣是O(n2log?n)O(n^2\log n)O(n2logn)的比暴力還慢…
乘起來比較慢,如果lnlnln之后改成加法就好了,但是lnlnln也是O(n)O(n)O(n)的。不過我們的式子比較特殊,對于lnlnln之后求個導(dǎo)就會有神器的結(jié)果
ln′(1?xv)=(1?xv)′1?xv=?v×xv?11?xvln'(1-x^v)=\frac{(1-x^v)'}{1-x^v}=\frac{-v\times x^{v-1}}{1-x^v}ln′(1?xv)=1?xv(1?xv)′?=1?xv?v×xv?1?
=?v∑i≥0xv?1+v×i=-v\sum_{i\geq 0}x^{v-1+v\times i}=?vi≥0∑?xv?1+v×i
然后在積分回去就是
?∑i≥0xv+v×ii=?∑i≥1xv×ii-\sum_{i\geq 0}\frac{x^{v+v\times i}}{i}=-\sum_{i\geq 1}\frac{x^{v\times i}}{i}?i≥0∑?ixv+v×i?=?i≥1∑?ixv×i?
然后記錄每個大小的物品出現(xiàn)了多少次,之后O(mlog?m)O(m\log m)O(mlogm)加系數(shù),然后再exp+exp+exp+求逆回去就好了。
時間復(fù)雜度O(n+mlog?m)O(n+m\log m)O(n+mlogm)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=4e5+10,P=998244353; ll n,c,l,r[N],f[N],v[N],inv[N]; ll t1[N],t2[N],t3[N],t4[N],t5[N],t6[N]; ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%P;x=x*x%P;b>>=1;}return ans; } void Glen(ll m){n=1;while(n<=m)n<<=1;for(ll i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)?(n>>1):0);return; } void NTT(ll *f,ll op){for(ll i=0;i<n;i++)if(i<r[i])swap(f[i],f[r[i]]);for(ll p=2;p<=n;p<<=1){ll len=p>>1,tmp=power(3,(P-1)/p);if(op==-1)tmp=power(tmp,P-2);for(ll k=0;k<n;k+=p){ll buf=1;for(ll i=k;i<k+len;i++){ll tt=f[i+len]*buf%P;f[i+len]=(f[i]-tt+P)%P;f[i]=(f[i]+tt)%P;buf=buf*tmp%P;}}}if(op==-1){ll inv=power(n,P-2);for(ll i=0;i<n;i++)f[i]=f[i]*inv%P;}return; } void GetInv(ll *f,ll *g,ll m){if(m==1){g[0]=power(f[0],P-2);return;}GetInv(f,g,m>>1);Glen(m);for(ll i=0;i<m;i++)t1[i]=f[i],t2[i]=g[i];NTT(t1,1);NTT(t2,1);for(ll i=0;i<n;i++)t1[i]=t1[i]*t2[i]%P*t2[i]%P;NTT(t1,-1);for(ll i=0;i<m;i++)g[i]=(g[i]*2-t1[i]+P)%P;for(ll i=0;i<n;i++)t1[i]=t2[i]=0;return; } void GetD(ll *f,ll *g,ll n){for(ll i=0;i<n-1;i++)g[i]=f[i+1]*(i+1)%P;g[n-1]=0;return; } void GetJ(ll *f,ll *g,ll n){for(ll i=n-1;i>0;i--)g[i]=f[i-1]*power(i,P-2)%P;g[0]=0;return; } void GetLn(ll *f,ll *g,ll m){Glen(m);GetD(f,t3,n);GetInv(f,t4,n);Glen(m);Glen(n);NTT(t3,1);NTT(t4,1);for(ll i=0;i<n;i++)t3[i]=t3[i]*t4[i];NTT(t3,-1);GetJ(t3,g,n);for(ll i=0;i<n;i++)t3[i]=t4[i]=0;return; } void GetExp(ll *f,ll *g,ll m){if(m==1){g[0]=1;return;}GetExp(f,g,m>>1);GetLn(g,t5,m);Glen(m);for(ll i=0;i<m;i++)t6[i]=f[i];for(ll i=m;i<n;i++)t5[i]=0;NTT(t5,1);NTT(t6,1);NTT(g,1);for(ll i=0;i<n;i++)g[i]=g[i]*(1-t5[i]+t6[i]+P)%P;NTT(g,-1);for(ll i=m;i<n;i++)g[i]=0;return; } signed main() {scanf("%lld%lld",&c,&l);inv[1]=1;for(ll i=2;i<N;i++)inv[i]=P-(P/i)*inv[P%i]%P;for(ll i=1;i<=c;i++){ll x;scanf("%lld",&x);v[x]++;}Glen(l);for(ll i=l;i>=1;i--){ll w=v[i];v[i]=0;for(ll j=i;j<n;j+=i)(v[j]+=w*(P-inv[j/i])%P)%=P;}ll p=n;GetExp(v,f,n);for(ll i=0;i<n;i++)v[i]=0;GetInv(f,v,n);for(ll i=1;i<=l;i++)printf("%lld\n",v[i]);return 0; }總結(jié)
以上是生活随笔為你收集整理的P4389-付公主的背包【生成函数,多项式exp】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么查看需要回答问题的qq相册
- 下一篇: P4345-[SHOI2015]超能粒子