【洛谷4389】付公主的背包(生成函数,多项式运算)
【洛谷4389】付公主的背包(生成函數(shù),多項式運算)
題面
有一個容量最多為\(10^5\)的背包
有\(n\)種物品,數(shù)量無限,題解是\(v_i\)
給定一個\(m\),求所有\(s\in[1,m]\),恰好裝滿容積為\(s\)的背包的方案數(shù)。
\(n,v_i,m<=10^5\)
題解
這題太神了,無限\(orz\)出題人
\(30\)分的部分分很顯然就是一個背包。并沒有什么好說的。
純隨機的數(shù)據(jù)并不知道怎么亂搞。
所以我直接寫我的方法了。。。。
既然背包做不了,又是求一類計數(shù)問題的答案,再加上我最近正好再做生成函數(shù)這一套理論。這道題目就往這方面想了。
我們假設物品的數(shù)量比較少,來看看怎么做這道題目。首先每個物品的個數(shù)可以直接看成無限,那么對于一個體積為\(V\)的物品,我們可以直接構建生成函數(shù)。
\[A(x)=\sum_{i=0}^{\infty}[i\%V=0]x^i=\frac{1}{1-x^V}\]
顯然答案就是\(m\)個生成函數(shù)的卷積。
如果直接做答案是\(O(mnlogn)\),顯然不是正確的復雜度。
我們看看怎么優(yōu)化。
生成函數(shù)除了形式冪級數(shù)的形式還有封閉形式,我在\(A(x)\)的后面已經(jīng)寫出了封閉形式,所以只需要把封閉形式的卷積求出來,然后求個逆還原多項式就行了。
但是這樣的復雜度是\(O(2^m)\),還是\(GG\)
我們要考慮一個方法,能夠把乘法化簡。很自然的想到同時取對數(shù)之后就變成了加法,但是多項式求\(ln\)的復雜度也是\(O(nlogn)\)的,但是我們的多項式很特殊,打表后發(fā)現(xiàn)它的\(ln\)是一個特殊形式,也就是
\[\sum_{i=0}^{\infty}[i\%V=0]\frac{-1}{i/v}x^i\]
于是,統(tǒng)計每一個容量的物品個數(shù),然后\(O(m/V)\)給對應的位置加上系數(shù),這樣總的復雜度是\(O(nlogn)\)的。
做完這一步相當于給每個封閉形式求\(ln\)之后求完了和。
直接多項式\(exp\)再多項式求逆之后還原多項式,輸出答案即可。
提供我的大常數(shù)代碼。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAX 277777 const int MOD=998244353; const int Phi=MOD-1; const int gr=3; inline int read() {RG int x=0,t=1;RG char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')t=-1,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*t; } int fpow(int a,int b) {int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s; } int r[MAX],N,l,M; int Og[MAX]; void NTT(int *P,int opt,int n) {for(N=1,l=0;N<n;N<<=1)++l;for(RG int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));for(RG int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);for(RG int i=1;i<N;i<<=1){RG int W=fpow(gr,Phi/(i<<1));Og[0]=1;for(RG int j=1;j<i;++j)Og[j]=1ll*Og[j-1]*W%MOD;for(RG int p=i<<1,j=0;j<N;j+=p)for(RG int k=0;k<i;++k){RG int X=P[j+k],Y=1ll*Og[k]*P[i+j+k]%MOD;P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD;}}if(opt==-1){reverse(&P[1],&P[N]);for(RG int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;} } int inv[MAX]; void initinv(int N) {inv[0]=inv[1]=1;for(RG int i=2;i<N;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD; } int A[MAX],B[MAX]; void Inv(int *a,int *b,int len) {if(len==1){b[0]=fpow(a[0],MOD-2);return;}Inv(a,b,len>>1);for(RG int i=0;i<len;++i)A[i]=a[i],B[i]=b[i];NTT(A,1,len<<1);NTT(B,1,len<<1);for(RG int i=0;i<(len<<1);++i)A[i]=1ll*A[i]*B[i]%MOD*B[i]%MOD;NTT(A,-1,len<<1);for(RG int i=0;i<len;++i)b[i]=(b[i]+b[i])%MOD;for(RG int i=0;i<len;++i)b[i]=(b[i]+MOD-A[i])%MOD;for(RG int i=0;i<(len<<1);++i)A[i]=B[i]=0; } int C[MAX],D[MAX]; void Dao(int *a,int *b,int len) {for(RG int i=1;i<len;++i)b[i-1]=1ll*i*a[i]%MOD;b[len]=b[len-1]=0; } void Jifen(int *a,int *b,int len) {for(RG int i=1;i<len;++i)b[i]=1ll*a[i-1]*inv[i]%MOD;b[0]=0; } void Getln(int *a,int *b,int len) {int A[MAX],B[MAX];memset(A,0,sizeof(A));memset(B,0,sizeof(B));Dao(a,A,len);Inv(a,B,len);NTT(A,1,len<<1);NTT(B,1,len<<1);for(RG int i=0;i<(len<<1);++i)A[i]=1ll*A[i]*B[i]%MOD;NTT(A,-1,len<<1);Jifen(A,b,len);for(RG int i=0;i<(len<<1);++i)A[i]=B[i]=0; } int E[MAX]; void Exp(int *a,int *b,int len) {if(len==1){b[0]=1;return;}Exp(a,b,len>>1);for(RG int i=0;i<len;++i)D[i]=b[i];Getln(b,E,len);for(RG int i=0;i<len;++i)E[i]=(MOD-E[i]+a[i])%MOD;E[0]=(E[0]+1)%MOD;NTT(E,1,len<<1);NTT(D,1,len<<1);for(RG int i=0;i<(len<<1);++i)D[i]=1ll*D[i]*E[i]%MOD;NTT(D,-1,len<<1);for(RG int i=0;i<len;++i)b[i]=D[i];for(RG int i=0;i<(len<<1);++i)D[i]=E[i]=0; } void FastPow(int *a,int *b,int K,int len) {int E[MAX];memset(E,0,sizeof(E));Getln(a,E,len);for(RG int i=0;i<len;++i)E[i]=1ll*K*E[i]%MOD;Exp(E,b,len); } int X[MAX],Y[MAX]; int n,K,TT[MAX],m; int main() {n=read();m=read();for(int i=1;i<=n;++i)TT[read()]++;int N;for(N=1;N<=m;N<<=1);initinv(N);for(int i=1;i<=m;++i)if(TT[i])for(int j=i;j<N;j+=i)X[j]=(X[j]+1ll*TT[i]*(MOD-inv[j/i]))%MOD;Exp(X,Y,N);memset(X,0,sizeof(X));Inv(Y,X,N);for(int i=1;i<=m;++i)printf("%d\n",X[i]);return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/cjyyb/p/8798495.html
總結
以上是生活随笔為你收集整理的【洛谷4389】付公主的背包(生成函数,多项式运算)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spark源码编译
- 下一篇: 中小型研发团队架构实践:集中式日志ELK