日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

指数型生成函数[bzoj3456]城市规划

發布時間:2024/4/11 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 指数型生成函数[bzoj3456]城市规划 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

打完多項式板子后的第一題+清真的題意

題目相關

題目鏈接

題目大意

nnn個點的簡單(無重邊無自環)無向連通圖數目
輸出模1004535809(479?221+1)1004535809(479*2^{21}+1)1004535809(479?221+1)

數據范圍

n≤130000n\le 130000n130000

題解

暴力

我只推出了個暴力,感覺和多項式沒啥關系
如果沒有任何限制,那么答案為2Cn22^{C_n^2}2Cn2?
FnF_nFn?為答案,寫出遞推式(用所有的方案數減去不連通的方案數,枚舉最后一個點所處的聯通塊大小即可)
Fi=2Ci2?∑j=1i?1Fj?Ci?1j?1?2Ci?j2F_i=2^{C_i^2}-\sum_{j=1}^{i-1}F_j*C_{i-1}^{j-1}*2^{C_{i-j}^2}Fi?=2Ci2??j=1i?1?Fj??Ci?1j?1??2Ci?j2?
遞推+快速冪
復雜度O(n2logp)\mathcal O(n^2logp)O(n2logp)
要是沒有代碼長度限制就可以打表過了(大霧)

正解

和暴力幾乎沒啥關系
考慮指數型生成函數
我們來觀察指數型生成函數的性質,列出兩個指數型生成函數
A(x)=∑i=0∞aixii!A(x)=\sum_{i=0}^{\infty}a_i\frac{x^i}{i!}A(x)=i=0?ai?i!xi?
B(x)=∑i=0∞bixii!B(x)=\sum_{i=0}^{\infty}b_i\frac{x^i}{i!}B(x)=i=0?bi?i!xi?
我們觀察一下A(x)?B(x)A(x)·B(x)A(x)?B(x)
A(x)?B(X)=(∑i=0∞aixii!)?(∑i=0∞bixii!)=∑i=0∞aixii!∑j=0∞bjxjj!=∑i=0∞∑j=0∞aixii!bjxjj!=∑n=0∞(∑i=0∞(ni)aibn?i)xnn!\begin{aligned} A(x)·B(X)&=(\sum_{i=0}^{\infty}a_i\frac{x^i}{i!})·(\sum_{i=0}^{\infty}b_i\frac{x^i}{i!})\\ &=\sum_{i=0}^{\infty}a_i\frac{x^i}{i!}\sum_{j=0}^{\infty}b_j\frac{x^j}{j!}\\ &=\sum_{i=0}^{\infty}\sum_{j=0}^{\infty}a_i\frac{x^i}{i!}b_j\frac{x^j}{j!}\\ &=\sum_{n=0}^{\infty}(\sum_{i=0}^{\infty}\binom{n}{i}a_ib_{n-i})\frac{x^n}{n!}\\ \end{aligned} A(x)?B(X)?=(i=0?ai?i!xi?)?(i=0?bi?i!xi?)=i=0?ai?i!xi?j=0?bj?j!xj?=i=0?j=0?ai?i!xi?bj?j!xj?=n=0?(i=0?(in?)ai?bn?i?)n!xn??
發現這個形式非常的奇妙
如果aia_iai?代表在第一個集合中選iii個的方案數,bib_ibi?代表在第二個集合中選iii個的方案數
那么相乘后我們就可以知道總共選iii個的方案數

考慮劃分
我們發現,如果我們按照劃分出一個大小為iii的集合的方案數建一個指數型生成函數F(x)F(x)F(x)
那么我們就能計算出對于nnn個元素劃分成mmm個集合的方案數
對于m=0m=0m=0,答案的多項式為111(即只有n=0n=0n=0時方案數為111
對于m=1m=1m=1,答案多項式為F(x)1!\frac{F(x)}{1!}1!F(x)?
對于m=2m=2m=2,答案多項式為F2(x)2!\frac{F^2(x)}{2!}2!F2(x)?
對于m=3m=3m=3,答案多項式為F3(x)3!\frac{F^3(x)}{3!}3!F3(x)?
···
由于劃分先后的問題,所以要除以階乘
如果我們要求每個nnn的劃分總方案數
F0(x)0!+F1(x)1!+F(x)2!???=∑i=0∞Fi(x)i!\frac{F^0(x)}{0!}+\frac{F^1(x)}{1!}+\frac{F^(x)}{2!}···=\sum_{i=0}^\infty \frac{F^i(x)}{i!}0!F0(x)?+1!F1(x)?+2!F(x)????=i=0?i!Fi(x)?
根據底數為eee的泰勒展開式ex=∑i=0∞xii!e^x=\sum_{i=0}^\infty\frac {x^i}{i!}ex=i=0?i!xi?
我們得到∑i=0∞Fi(x)i!=eF(x)\sum_{i=0}^\infty \frac{F^i(x)}{i!}=e^{F(x)}i=0?i!Fi(x)?=eF(x)


回到本題: 我們思考,在這一題中,所有聯通圖都是無限制圖的一個劃分
F(x)F(x)F(x)為聯通圖方案數的多項式,G(x)G(x)G(x)為無限制圖方案數的多項式
容易發現eF(x)=G(x)e^{F(x)}=G(x)eF(x)=G(x)
所以F(x)=ln(G(x))F(x)=ln(G(x))F(x)=ln(G(x))
我們發現G(x)G(x)G(x)非常好求(暴力的那部分已經說過了)
然后直接多項式ln即可

代碼

拉了板子所以代碼很長

#include<cstdio> #include<cctype> #include<cstring> #include<cstdlib> #include<vector> namespace fast_IO {const int IN_LEN=10000000,OUT_LEN=10000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf,1,oh-obuf,stdout);} } using namespace fast_IO; #define getchar() getchar_() #define putchar(x) putchar_((x)) typedef long long ll; #define rg register template <typename T> inline T max(const T a,const T b){return a>b?a:b;} template <typename T> inline T min(const T a,const T b){return a<b?a:b;} template <typename T> inline T mind(T&a,const T b){a=a<b?a:b;} template <typename T> inline T maxd(T&a,const T b){a=a>b?a:b;} template <typename T> inline T abs(const T a){return a>0?a:-a;} template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;} template <typename T> inline void swap(T*a,T*b){T c=a;a=b;b=c;} template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);} template <typename T> inline T square(const T x){return x*x;}; template <typename T> inline void read(T&x) {char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x; } template <typename T> void printe(const T x) {if(x>=10)printe(x/10);putchar(x%10+'0'); } template <typename T> inline void print(const T x) {if(x<0)putchar('-'),printe(-x);else printe(x); } const int maxn=2097152,mod=1004535809; inline int Md(const int x){return x>=mod?x-mod:x;} template<typename T> inline int pow(int x,T y) {rg int res=1;x%=mod;for(;y;y>>=1,x=(ll)x*x%mod)if(y&1)res=(ll)res*x%mod;return res; } namespace Poly///namespace of Poly { int W_[maxn],FW_[maxn],ha[maxn],hb[maxn],Inv[maxn]; inline void init(const int x) {rg int tim=0,lenth=1;while(lenth<x)lenth<<=1,tim++;for(rg int i=1;i<lenth;i++){W_[i]=pow(3,(mod-1)/i/2);FW_[i]=pow(W_[i],mod-2);}Inv[0]=Inv[1]=1;for(rg int i=2;i<x;i++)Inv[i]=(ll)(mod-mod/i)*Inv[mod%i]%mod; } int L; inline void NTT(int*A,const int fla)//prepare:init L {for(rg int i=0,j=0;i<L;i++){if(i>j)swap(A[i],A[j]);for(rg int k=L>>1;(j^=k)<k;k>>=1);}for(rg int i=1;i<L;i<<=1){const int w=fla==-1?FW_[i]:W_[i];for(rg int j=0,J=i<<1;j<L;j+=J){int K=1;for(rg int k=0;k<i;k++,K=(ll)K*w%mod){const int x=A[j+k],y=(ll)A[j+k+i]*K%mod;A[j+k]=Md(x+y),A[j+k+i]=Md(mod+x-y);}}} } inline int Quadratic_residue(const int a) {if(a==0)return 0;int b=(rand()<<14^rand())%mod;while(pow(b,(mod-1)>>1)!=mod-1)b=(rand()<<14^rand())%mod;int s=mod-1,t=0,x,inv=pow(a,mod-2),f=1;while(!(s&1))s>>=1,t++,f<<=1;t--,x=pow(a,(s+1)>>1),f>>=1;while(t){f>>=1;if(pow((int)((ll)inv*x%mod*x%mod),f)!=1)x=(ll)x*pow(b,s)%mod;t--,s<<=1;}return min(x,mod-x); } struct poly {std::vector<int>A;poly(){A.resize(0);}poly(const int x){A.resize(1),A[0]=x;}inline int&operator[](const int x){return A[x];}inline int operator[](const int x)const{return A[x];}inline void clear(){A.clear();}inline unsigned int size()const{return A.size();}inline void resize(const unsigned int x){A.resize(x);}void RE(const int x){A.resize(x);for(rg int i=0;i<x;i++)A[i]=0; }void readin(const int MAX){A.resize(MAX);for(rg int i=0;i<MAX;i++)read(A[i]);}void putout()const{for(rg unsigned int i=0;i<A.size();i++)print(A[i]),putchar(' ');}inline poly operator +(const poly b)const{poly RES;RES.resize(max(size(),b.size()));for(rg unsigned int i=0;i<RES.size();i++)RES[i]=Md((i<size()?A[i]:0)+(i<b.size()?b[i]:0));return RES;}inline poly operator -(const poly b)const{poly RES;RES.resize(max(size(),b.size()));for(rg unsigned int i=0;i<RES.size();i++)RES[i]=Md((i<size()?A[i]:0)+mod-(i<b.size()?b[i]:0));return RES;}inline poly operator *(const int b)const{poly RES=*this;for(rg unsigned int i=0;i<RES.size();i++)RES[i]=(ll)RES[i]*b%mod;return RES;}inline poly operator /(const int b)const{poly RES=(*this)*pow(b,mod-2);return RES;}inline poly operator *(const poly b)const{const int RES=A.size()+b.size()+1;L=1;while(L<RES)L<<=1;poly c;c.A.resize(RES);memset(ha,0,sizeof(int)*L);memset(hb,0,sizeof(int)*L);for(rg unsigned int i=0;i<A.size();i++)ha[i]=A[i];for(rg unsigned int i=0;i<b.A.size();i++)hb[i]=b.A[i];NTT(ha,1),NTT(hb,1);for(rg int i=0;i<L;i++)ha[i]=(ll)ha[i]*hb[i]%mod;NTT(ha,-1);const int inv=pow(L,mod-2);for(rg int i=0;i<RES;i++)c.A[i]=(ll)ha[i]*inv%mod;return c;}inline poly inv()const{poly C;if(A.size()==1){C=*this;C[0]=pow(C[0],mod-2);return C;}C.resize((A.size()+1)>>1);for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i];C=C.inv();L=1;while(L<(int)size()*2-1)L<<=1;for(rg unsigned int i=0;i<A.size();i++)ha[i]=A[i];for(rg unsigned int i=0;i<C.size();i++)hb[i]=C[i];memset(ha+A.size(),0,sizeof(int)*(L-A.size()));memset(hb+C.size(),0,sizeof(int)*(L-C.size()));NTT(ha,1),NTT(hb,1);for(rg int i=0;i<L;i++)ha[i]=(ll)(2-(ll)hb[i]*ha[i]%mod+mod)*hb[i]%mod;NTT(ha,-1);const int inv=pow(L,mod-2);C.resize(size());for(rg unsigned int i=0;i<size();i++)C[i]=(ll)ha[i]*inv%mod;return C;} /* inline poly inv()const{poly C;if(A.size()==1){C=*this;C[0]=pow(C[0],mod-2);return C;}C.resize((A.size()+1)>>1);for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i];C=C.inv();poly D=(poly)2-*this*C;D.resize(size());D=D*C;D.resize(size());return D;}*///大常數版本 inline void Reverse(const int n){A.resize(n);for(rg int i=0,j=n-1;i<j;i++,j--)swap(A[i],A[j]);}inline poly operator /(const poly B)const{poly a=*this,b=B;a.Reverse(size()),b.Reverse(B.size());b.resize(size()-B.size()+1);b=b.inv();b=b*a;b.Reverse(size()-B.size()+1);return b;}inline poly operator %(const poly B)const{poly C=(*this)-(*this)/B*B;C.resize(B.size()-1);return C;}inline poly diff()const{poly C;C.resize(size()-1);for(rg unsigned int i=1;i<size();i++)C[i-1]=(ll)A[i]*i%mod;return C;}inline poly inte()const{poly C;C.resize(size()+1);for(rg unsigned int i=0;i<size();i++)C[i+1]=(ll)A[i]*Inv[i+1]%mod;C[0]=0;return C;}inline poly ln()const{poly C=(diff()*inv()).inte();C.resize(size());return C;}inline poly exp()const{poly C;if(size()==1){C=*this;C[0]=1;return C;}C.resize((size()+1)>>1);for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i];C=C.exp();C.resize(size());poly D=(poly)1-C.ln()+*this;D=D*C;D.resize(size());return D;}inline poly sqrt()const{poly C;if(size()==1){C=*this;C[0]=Quadratic_residue(C[0]);return C;}C.resize((size()+1)>>1);for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i];C=C.sqrt();C.resize(size());C=(C+*this*C.inv())*(int)499122177;C.resize(size());return C;}inline poly operator >>(const unsigned int x)const{poly C;if(size()<x){C.resize(0);return C;}C.resize(size()-x);for(rg unsigned int i=0;i<C.size();i++)C[i]=A[i+x];return C;}inline poly operator <<(const unsigned int x)const{poly C;C.RE(size()+x);for(rg unsigned int i=0;i<size();i++)C[i+x]=A[i];return C;}inline poly Pow(const unsigned int x)const{for(rg unsigned int i=0;i<size();i++)if(A[i]){poly C=((((*this/A[i])>>i).ln()*x).exp()*pow(A[i],x))<<(min(i*x,size()));C.resize(size());return C;}return *this;} }; }///namespace of Poly Poly::poly a; int n; int fac[maxn+1],inv[maxn+1]; int main() {fac[0]=1;for(rg int i=1;i<=maxn;i++)fac[i]=(ll)fac[i-1]*i%mod;inv[maxn]=pow(fac[maxn],mod-2);for(rg int i=maxn;i>=1;i--)inv[i-1]=(ll)inv[i]*i%mod;Poly::init(maxn);///namespace of Polyread(n);a.RE(n+1);for(rg int i=0;i<=n;i++)a[i]=(ll)pow(2,((ll)i*(i-1))>>1)*inv[i]%mod;a=a.ln();print((ll)a[n]*fac[n]%mod);return flush(),0; }

總結

好推+好用的指數型生成函數!

總結

以上是生活随笔為你收集整理的指数型生成函数[bzoj3456]城市规划的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。