并不对劲的bzoj5475:loj2983:p5206:[wc2019]数树
題目大意
task0:有兩棵\(n\)(n\leq10^5)個(gè)點(diǎn)的樹\(T1,T2\),每個(gè)點(diǎn)的點(diǎn)權(quán)可以是一個(gè)在\([1,y]\)里的數(shù),如果兩個(gè)點(diǎn)既在\(T1\)中有直接連邊,又在\(T2\)中有直接連邊,那么它們的點(diǎn)權(quán)必須相同。求有多少種分配點(diǎn)權(quán)的方案。
task1:有一棵\(n\)個(gè)點(diǎn)的樹\(T1\),給定\(y\),求\(T2\)所有形態(tài)的task1之和\(mod 998244353\)
task2:給定\(n,y\),求\(T1\)所有形態(tài)的task2之和\(mod 998244353\)
題解
這個(gè)人(點(diǎn)這里或點(diǎn)這里)講得很清楚
首先,當(dāng)\(y=1\)時(shí),所有點(diǎn)權(quán)都得是1,task0的答案就是1,task1的答案就是\(n^{n-2}\),task2的答案就是\(n^{2*n-4}\)
task0
設(shè)森林\(T3=T1\bigcap T2\)
那么就會(huì)發(fā)現(xiàn)\(T3\)中同一個(gè)連通塊內(nèi)的所有點(diǎn)的點(diǎn)權(quán)必須相等,分配點(diǎn)權(quán)的方案數(shù)為\(y^{n-|T3|}\)
task1
枚舉\(T2\)的話,設(shè)\(x=y^{-1}\),答案=\(\sum\limits_{T2}y^{n-m}=\sum\limits_{T2}y^n*x^{|T3|}\)
給定\(n\)的情況下,\(y^n\)不變,只考慮怎么算\(x^{|T3|}\)
通過查看題解 根據(jù)二項(xiàng)式定理發(fā)現(xiàn)\(y^n*x^{|T3|}=y^n*(x-1+1)^{|T3|}=y^n*\sum\limits_{i=0}^{|T3|}{C_{|T3|}^{i}*(x-1)^i}\)
考慮枚舉\(T4\subseteq T3\),則每個(gè)\(T4\)對上式的貢獻(xiàn)是\(y^n*(x-1)^{|T4|}\)(相當(dāng)于在\(|T3|\)條邊中選了\(|T4|\)條邊)
原式就變成了:答案=\(\sum\limits_{T2}\sum\limits_{T4\subseteq(T1\bigcap T2)}y^n*(x-1)^{|T4|}\)
枚舉\(T4\)的\(\Sigma\)拿到前面,則有\(\sum\limits_{T4\subseteq T1}y^n*(x-1)^{|T4|}\sum\limits_{E\not\subset T4 且 |E|+|T4|=n}1\)
相當(dāng)于對于每個(gè)\(T4\),它的貢獻(xiàn)就是把它這個(gè)森林連成樹的方案數(shù)
枚舉\(T4\)的連通塊個(gè)數(shù),則有\(\sum\limits_{m=1}^{n}\sum\limits_{n-|T4|=m且T4\subseteq T1}y^n*(x-1)^{n-m}\sum\limits_{E\not\subset T4 且 |E|+|T4|=n}1\)
這樣就能把和\(x,y\)有關(guān)的部分拿到前面了:\(\sum\limits_{m=1}^{n}y^n*(x-1)^{n-m}\sum\limits_{n-|T4|=m且T4\subseteq T1}\sum\limits_{E\not\subset T4 且 |E|+|T4|=n-1}1\)
設(shè)\(T4\)的\(m\)個(gè)連通塊里的點(diǎn)數(shù)分別為\(a_1,a_2,...,a_m\),枚舉每個(gè)連通塊的度數(shù)\(d_1,d_2,...,d_m\)
先把\(T4\)的\(m\)個(gè)連通塊看成\(m\)個(gè)點(diǎn),那么就相當(dāng)于要求出\(m\)個(gè)點(diǎn)的有標(biāo)號無根樹有多少棵
這個(gè)可以用prufer序列相關(guān)的定理算出是\(m^{m-2}\)棵
設(shè)prufer序列中\(i\)的出現(xiàn)次數(shù)是\(d_i\)
\(m\)個(gè)連通塊與\(m\)個(gè)點(diǎn)的區(qū)別在于,\(m\)個(gè)點(diǎn)的話,點(diǎn)\(i\)要連\(d_i+1\)條邊;而\(m\)個(gè)連通塊的話,連向連通塊\(i\)的\(d_i+1\)條邊的每一條邊都可以在\(a_i\)個(gè)點(diǎn)中任選一個(gè)連邊,總方案數(shù)要再乘上個(gè)\(\prod\limits_{i=1}^{m}a_i^{d_i+1}\)
枚舉prufer序列,假設(shè)prufer序列是\(p_1,p_2,...,p_m\),就會(huì)有\(m\)個(gè)連通塊,第\(i\)個(gè)連通塊\(a_i\)個(gè)點(diǎn)的有標(biāo)號無根樹有\(\sum\limits_{p_1,p_2,...,p_{m-2}, 1\leq p_i\leq m}\prod\limits_{i=1}^{m}a_i^{d_i+1}\)棵
把指數(shù)\(d_i+1\)中“+1”的那個(gè)\(a_i\)拿到前面,該式=\((\prod\limits_{i=1}^{m}a_i)*\sum\limits_{p_1,p_2,...,p_{m-2}, 1\leq p_i\leq m}\prod\limits_{i=1}^{m}a_i^{d_i}\)
這樣變化之后,枚舉的prufer序列中每個(gè)出現(xiàn)的\(p_i\)都會(huì)對該式有\(a_{p_i}\)的貢獻(xiàn)
就會(huì)有該式=\((\prod\limits_{i=1}^{m}a_i)*\sum\limits_{p_1,p_2,...,p_{m-2}, 1\leq p_i\leq m}\prod\limits_{i=1}^{m-2}a_{p_i}\)
交換\(\sum\)和\(\prod\),得該式=\((\prod\limits_{i=1}^{m}a_i)*\prod\limits_{i=1}^{m-2}\sum\limits_{p_i=1}^{m}a_{p_i}\)
其中\(\sum\limits_{p_i=1}^{m}a_{p_i}=n\)
那么該式=\((\prod\limits_{i=1}^{m}a_i)*n^{m-2}\)
就會(huì)有:答案=\(\sum\limits_{m=1}^{n}y^n*(x-1)^{n-m}\sum\limits_{\sum a_i=n}(\prod\limits_{i=1}^{m}a_i)*n^{m-2}\)
將與\(m\)有關(guān)的部分都挪到后面,與\(n\)有關(guān)的挪到前面,得:答案=\(y^n*(x-1)^n*n^{-2} \sum\limits_{\sum a_i=n}(\prod\limits_{i=1}^{m}a_i)*n^{m}*(x-1)^{-m}\)
將\(n^{m}*(x-1)^{-m}\)拿到\(\prod\)中,得:答案=\(y^n*(x-1)^n*n^{-2} \prod\limits_{i=1}^{m}(a_i*(x-1)^{-1}*n)\)
其中\(\prod\limits_{i=1}^{m}a_i\)的部分相當(dāng)于將\(n\)個(gè)點(diǎn)劃分成一些連通塊,在每一個(gè)連通塊中選一個(gè)關(guān)鍵點(diǎn)的方案數(shù)
這個(gè)可以dp,設(shè)\(f(i,0/1)\)表示以\(i\)為根的子樹中,\(i\)所在連通塊有/沒有選出關(guān)鍵點(diǎn)的方案數(shù)
那么\(\prod\limits_{i=1}^{m}(a_i*(x-1)^{-1}*n)\)可以看成在此基礎(chǔ)上,每個(gè)連通塊又乘了\((x-1)^{-1}*n\),這個(gè)也可以dp
答案=\(y^n*(x-1)^n*n^{-2}*f(1,1)\)
task2
既要枚舉\(T2\),又要枚舉\(T1\)
可以把答案看成“\(n\)個(gè)有標(biāo)號的點(diǎn)分\(m\)個(gè)無標(biāo)號的組的方案數(shù)”、“\(m\)個(gè)連通塊中每個(gè)連通塊能構(gòu)出多少棵樹”、“確定塊內(nèi)的連邊情況后,T1的塊間連通方案數(shù)”、“確定塊內(nèi)的連邊情況后,T2的塊間連通方案數(shù)”四部分相乘
“\(n\)個(gè)有標(biāo)號的點(diǎn)分\(m\)個(gè)無標(biāo)號的組的方案數(shù)”=\(\sum\limits_{\sum{a_i}=n}{\frac{n!}{m!*\prod_{i=1}^{m}{a_i!}}}\)
根據(jù)prufer序列,\(x\)個(gè)點(diǎn)的連通塊構(gòu)出\(x^{x-2}\)棵樹,考慮\(m\)個(gè)連通塊中每個(gè)連通塊都能構(gòu)出\(a_i^{a_i}\)棵樹,“\(m\)個(gè)連通塊中每個(gè)連通塊能構(gòu)出多少棵樹”=\(\prod\limits_{i=1}^{m}{a_i^{a_i-2}}\)
而“確定塊內(nèi)的連邊情況后,T1/T2的塊間連通方案數(shù)”這部分之前已經(jīng)算過了,就是\((\prod\limits_{i=1}^{m}a_i)*n^{m-2}\)
所以,答案=\(y^n*(x-1)^{n-m}*\sum\limits_{\sum{a_i}=n}{\frac{n!}{m!*\prod\limits_{i=1}^{m}{a_i!}}}*(\prod\limits_{i=1}^{m}{a_i^{a_i-2}})*((\prod\limits_{i=1}^{m}a_i)*n^{m-2})^2\)
把\((n^{-2})^2\)拿到前面,把\((x-1)^{-m}\)拿到后面,將三個(gè)\(\prod\)合并,就會(huì)有:答案=\(y^n*(x-1)^n*n^{-4}*n!*\sum\limits_{\sum{a_i}=n}{\frac{1}{m!}}\prod\limits_{i=1}^{m}\frac{a_i^{a_i}*n^2}{a_i!*(x-1)}\)
用\([x^n]\)表示多項(xiàng)式中\(n\)次項(xiàng)的系數(shù),就會(huì)有:答案=\(y^n*(x-1)^n*n^{-4}*n!*[x^n]\sum\limits_{m=1}^{n}{\frac{1}{m!}}(\frac{n^2}{x-1}\sum\limits_{a>0}\frac{a^a}{a!}x^a)^m\)
根據(jù)泰勒展開發(fā)現(xiàn)\(exp(x)=\sum\limits_{i=0}^{\infty}\frac{x^i}{i!}\),那么\([x^n]\sum\limits_{m=1}^{n}{\frac{1}{m!}}(\frac{n^2}{x-1}\sum\limits_{a>0}\frac{a^a}{a!}x^a)^m\)這部分就可以看成\(exp(\frac{n^2}{x-1}\sum\limits_{a>0}\frac{a^a}{a!}x^a)\)
對這個(gè)多項(xiàng)式求exp后,將\(n\)次項(xiàng)系數(shù)乘以\(y^n*(x-1)^n*n!*n^{-4}\)
代碼
#include<algorithm> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #include<iomanip> #include<iostream> #include<map> #include<queue> #include<set> #include<stack> #include<vector> #define rep(i,x,y) for(register int i=(x);i<=(y);++i) #define dwn(i,x,y) for(register int i=(x);i>=(y);--i) #define view(u,k) for(int k=fir[u];~k;k=nxt[k]) #define maxn 100010 #define maxm (maxn<<1) #define maxlen (maxn<<3) #define LL long long #define mo(x) (x>=mod?x-mod:(x<0?x+mod:x)) using namespace std; int read() {int x=0,f=1;char ch=getchar();while(!isdigit(ch)&&ch!='-')ch=getchar();if(ch=='-')f=-1,ch=getchar();while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();return x*f; } void write(int x) {if(x==0){putchar('0'),putchar('\n');return;}int f=0;char ch[20];if(x<0)putchar('-'),x=-x;while(x)ch[++f]=x%10+'0',x/=10;while(f)putchar(ch[f--]);putchar('\n');return; } const LL mod=998244353; struct edge{int u,v;}e1[maxn],e2[maxn]; int f[maxn][2],fu[maxlen],ans[maxlen],fir[maxn],nxt[maxm],to[maxm],cnt,n,y,op,y2,ny2,t[2]; bool cmp(edge x,edge y){return x.u==y.u?x.v<y.v:x.u<y.u;} int mul(int a,int b){int ans=1;while(b){if(b&1)ans=(LL)ans*(LL)a%mod;a=(LL)a*(LL)a%mod;b>>=1;}return ans;} void ade(int u1,int v1){to[cnt]=v1,nxt[cnt]=fir[u1],fir[u1]=cnt++;} void getf(int u,int fa) {f[u][0]=f[u][1]=y2;view(u,k)if(to[k]!=fa){getf(to[k],u);t[0]=t[1]=0;rep(yesu,0,1)rep(yesv,0,1){if(!(yesu&yesv))t[yesu|yesv]=mo(t[yesu|yesv]+(LL)f[u][yesu]*(LL)f[to[k]][yesv]%mod*ny2%mod);if(yesv)t[yesu]=mo(t[yesu]+(LL)f[u][yesu]*(LL)f[to[k]][yesv]%mod);}f[u][0]=t[0],f[u][1]=t[1];} } int g[maxlen],h[maxlen],nowlen,nown,r[maxlen],tmp[maxlen],tmp2[maxlen]; void dnt(int * u,int fh) {rep(i,0,nown-1)r[i]=(r[i>>1]>>1)|((i&1)<<(nowlen-1));rep(i,0,nown-1)if(i<r[i])swap(u[i],u[r[i]]);for(int i=1;i<nown;i<<=1){int wn=mul(3,(mod-1)/(i<<1)); if(fh==-1)wn=mul(wn,mod-2);for(int j=0;j<nown;j+=(i<<1)){int w=1;rep(k,0,i-1){int a=u[j+k],b=(LL)w*(LL)u[i+j+k]%mod;u[j+k]=mo(a+b),u[i+j+k]=mo(a-b),w=(LL)w*(LL)wn%mod;}}}if(fh==-1){int inv=mul(nown,mod-2);rep(i,0,nown-1)u[i]=(LL)u[i]*(LL)inv%mod;}return; } void getny(int * u,int * v,int nlen) {v[0]=mul(u[0],mod-2);for(int len=0,tmpn=1;tmpn<nlen;len++,tmpn<<=1){nown=tmpn<<1,nowlen=len+1;rep(i,0,nown-1)tmp[i]=u[i];nown<<=1,nowlen++;rep(i,(tmpn<<1),nown-1)tmp[i]=0;dnt(tmp,1),dnt(v,1);rep(i,0,nown-1)v[i]=mo(2ll-(LL)tmp[i]*(LL)v[i]%mod)*(LL)v[i]%mod;dnt(v,-1);rep(i,(tmpn<<1),nown-1)v[i]=0;}rep(i,0,nown)tmp[i]=0; rep(i,nlen,nown)v[i]=0;return; } void getup(int * u,int * v,int nlen) {rep(i,1,nlen-1)v[i-1]=(LL)i*(LL)u[i]%mod;v[nlen-1]=0;return; } void getdx(int * u,int * v,int nlen) {rep(i,1,nlen-1)v[i]=(LL)u[i-1]*(LL)mul(i,mod-2)%mod;v[0]=0;return; } void getln(int * u,int * v,int nlen) {getup(u,h,nlen),getny(u,g,nlen);for(nowlen=0,nown=1;nown<(nlen+nlen);nowlen++,nown<<=1);dnt(h,1),dnt(g,1);rep(i,0,nown-1)h[i]=(LL)h[i]*(LL)g[i]%mod;rep(i,0,nown-1)g[i]=0;dnt(h,-1);getdx(h,v,nlen);rep(i,nlen,nown)v[i]=0;return; } void getexp(int * u,int * v,int nlen) {rep(i,0,(nlen<<2))v[i]=0;v[0]=1;for(int len=0,tmpn=1;tmpn<nlen;len++,tmpn<<=1){rep(i,0,(tmpn<<1))tmp2[i]=0;getln(v,tmp2,(tmpn<<1));nown=(tmpn<<2),nowlen=len+2;rep(i,(tmpn<<1),nown)tmp2[i]=0;rep(i,0,(tmpn<<1)-1)tmp[i]=u[i];rep(i,(tmpn<<1),nown)tmp[i]=0;dnt(tmp2,1),dnt(v,1),dnt(tmp,1);rep(i,0,nown-1)v[i]=(LL)v[i]*(LL)mo(mo(1ll-tmp2[i])+tmp[i])%mod;dnt(v,-1);rep(i,(tmpn<<1),nown)v[i]=0;}rep(i,nlen,nown)v[i]=0;return; } int main() {n=read(),y=read(),op=read();if(!op){rep(i,1,n-1){int x1=read(),y1=read();e1[i].u=min(x1,y1),e1[i].v=max(x1,y1);}rep(i,1,n-1){int x1=read(),y1=read();e2[i].u=min(x1,y1),e2[i].v=max(x1,y1);}sort(e1+1,e1+n,cmp),sort(e2+1,e2+n,cmp);int j=1;rep(i,1,n-1){while(cmp(e1[j],e2[i])&&j<n-1)j++;if(e1[j].u==e2[i].u&&e1[j].v==e2[i].v){cnt++;}}write(mul(y,n-cnt));}else if(op==1){memset(fir,-1,sizeof(fir));if(y==1){write(mul(n,n-2));return 0;} y2=(LL)mul((mul(y,mod-2)-1+mod)%mod,mod-2)*(LL)n%mod,ny2=mul(y2,mod-2);rep(i,1,n-1){int x1=read(),y1=read();ade(x1,y1),ade(y1,x1);}getf(1,0),write((LL)f[1][1]*(LL)mul((mul(y,mod-2)-1+mod)%mod,n)%mod*(LL)mul((LL)n*(LL)n%mod,mod-2)%mod*(LL)mul(y,n)%mod);}else {if(y==1){write(mul(n,n*2-4));return 0;}int facn=1,rfac,x=mul(y,mod-2),a=(LL)n*(LL)n%mod*(LL)mul(mo(x-1),mod-2)%mod;rep(i,2,n)facn=(LL)facn*(LL)i%mod;rfac=mul(facn,mod-2);dwn(i,n,1)fu[i]=(LL)rfac*(LL)mul(i,i)%mod*(LL)a%mod,rfac=(LL)rfac*(LL)i%mod;getexp(fu,ans,n+1);write((LL)mul(y,n)*(LL)mul((x-1+mod)%mod,n)%mod*(LL)mul((LL)n*(LL)n%mod*(LL)n%mod*(LL)n%mod,mod-2)%mod*(LL)facn%mod*(LL)ans[n]%mod);}return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/xzyf/p/10510133.html
總結(jié)
以上是生活随笔為你收集整理的并不对劲的bzoj5475:loj2983:p5206:[wc2019]数树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Linux] 020 RPM 包的命名
- 下一篇: Powerful Sleep(神奇的睡眠