L O J LOJ LOJ 传送门
-
转换一下题意得到:对于两棵树 T 1 , T 2 T1,T2 T1,T2,边集是 E 1 , E 2 E1,E2 E1,E2,那么贡献就是 y n − ∣ E 1 ∩ E 2 ∣ y^{n-|E1\cap E2|} yn−∣E1∩E2∣
-
第一问:直接求出并即可
-
第二问: T 1 T1 T1 确定,不妨来枚举 T 2 T2 T2
令 F ( S ) = ∑ T 2 [ T 1 ∩ T 2 = S ] F(S)=\sum_{T2} [T1\cap T2=S] F(S)=∑T2[T1∩T2=S]
这个直接求是很不好求的,但发现 G ( S ) = ∑ T 2 [ S ⊆ T 1 ∩ T 2 ] G(S)=\sum_{T2}[S\subseteq T1\cap T2] G(S)=∑T2[S⊆T1∩T2] 较为好求
因为我们钦定一个边集 S S S 表示 T 1 T1 T1 和 T 2 T2 T2 的并,剩下的边可以随便连,设 S S S 中连通块个数为 k k k,每个连通块大小为 a i a_i ai,那么任意连边连成一棵树的方案数就是 n k − 2 ∏ a i n^{k-2}\prod a_i nk−2∏ai -
引理: k k k 个大小分别为 a i a_i ai 的连通块连成一棵树的方案数是 n k − 2 ∏ a i n^{k-2}\prod a_i nk−2∏ai
考虑枚举 k k − 2 k^{k-2} kk−2 种 p r u f e r prufer prufer 序列,每一个序列的贡献是 ∏ i = 1 k a i d i + 1 \prod_{i=1}^{k}a_i^{d_i+1} ∏i=1kaidi+1, d i d_i di 为在序列中的出现次数,那么 w a y s = ( ∏ i = 1 k a i ) ∗ ( ∑ p r u f e r ∏ i = 1 k − 2 a p i ) = ( ∏ i = 1 k a i ) ∗ n k − 2 ways=(\prod_{i=1}^{k}a_i)*(\sum_{prufer}\prod_{i=1}^{k-2}a_{p_i})=(\prod_{i=1}^{k}a_i)*n^{k-2} ways=(∏i=1kai)∗(∑prufer∏i=1k−2api)=(∏i=1kai)∗nk−2,乘法分配率,意义显然 -
回到第二问
暴力把答案的式子写出来(把 y n y^n yn 提出来)
A n s = ∑ S ⊆ T 1 F ( S ) ∗ y − ∣ S ∣ = ∑ S ⊆ T 1 y − ∣ S ∣ ∑ S ⊆ T ⊆ T 1 ( − 1 ) ∣ T ∣ − ∣ S ∣ G ( T ) = ∑ T ⊆ T 1 ( − 1 ) ∣ T ∣ G ( T ) ∑ S ⊆ T ( − y ) − ∣ S ∣ = ∑ T ⊆ T 1 ( − 1 ) ∣ T ∣ G ( T ) ∑ i = 0 ∣ T ∣ ( − y ) − i ( ∣ T ∣ i ) = ∑ T ⊆ T 1 ( 1 y − 1 ) ∣ T ∣ G ( T ) = ∑ T ⊆ T 1 ( 1 y − 1 ) ∣ T ∣ n n − ∣ T ∣ − 2 ∏ i = 1 n − ∣ T ∣ a i = ( 1 y − 1 ) n n 2 ∑ T ⊆ T 1 ∏ i = 1 n − ∣ T ∣ a i ∗ n 1 y − 1 ( y ≠ 1 ) Ans=\sum_{S\subseteq T1}F(S)*y^{-|S|}\\=\sum_{S\subseteq T1}y^{-|S|}\sum_{S\subseteq T\subseteq T1}(-1)^{|T|-|S|}G(T)\\=\sum_{T\subseteq T1}(-1)^{|T|}G(T)\sum_{S\subseteq T}(-y)^{-|S|}\\ =\sum_{T\subseteq T1}(-1)^{|T|}G(T)\sum_{i=0}^{|T|}(-y)^{-i}\binom{|T|}{i}\\=\sum_{T\subseteq T1}(\frac{1}{y}-1)^{|T|}G(T)\\ =\sum_{T\subseteq T1}(\frac{1}{y}-1)^{|T|}n^{n-|T|-2}\prod_{i=1}^{n-|T|}a_i\\=\frac{(\frac{1}{y}-1)^n}{n^2}\sum_{T\subseteq T1}\prod_{i=1}^{n-|T|}\frac{a_i*n}{\frac{1}{y}-1}(y\neq 1) Ans=S⊆T1∑F(S)∗y−∣S∣=S⊆T1∑y−∣S∣S⊆T⊆T1∑(−1)∣T∣−∣S∣G(T)=T⊆T1∑(−1)∣T∣G(T)S⊆T∑(−y)−∣S∣=T⊆T1∑(−1)∣T∣G(T)i=0∑∣T∣(−y)−i(i∣T∣)=T⊆T1∑(y1−1)∣T∣G(T)=T⊆T1∑(y1−1)∣T∣nn−∣T∣−2i=1∏n−∣T∣ai=n2(y1−1)nT⊆T1∑i=1∏n−∣T∣y1−1ai∗n(y=1)
考虑后面这个式子的组合意义,就是在 T 1 T1 T1 中选择若干个连通块,每个连通块的贡献是 k ∗ a i k*a_i k∗ai,整个的贡献是所有连通块贡献之积,考虑树形 d p dp dp, f u , i f_{u,i} fu,i 表示到 u u u 当前连通块大小为 i i i 的所有方案的贡献之和,那么 w a y s = k ∑ i f 1 , i ways=k\sum if_{1,i} ways=k∑if1,i,暴力上生成函数, w a y s = k f ′ ( 1 ) ways=kf'(1) ways=kf′(1),并且有转移
f u ( x ) = f u ( x ) f v ( x ) + k f v ′ ( 1 ) ∗ f u ( x ) ⇒ k f u ′ ( x ) = k f ′ u ( x ) f v ( x ) + k f v ′ ( x ) f u ( x ) + k f v ′ ( 1 ) k f u ′ ( x ) f_u(x)=f_u(x)f_v(x)+kf'_v(1)*f_u(x)\\ \Rightarrow kf'_u(x)=kf'u(x)f_v(x)+kf'_v(x)f_u(x)+kf_v'(1)kf'_u(x) fu(x)=fu(x)fv(x)+kfv′(1)∗fu(x)⇒kfu′(x)=kf′u(x)fv(x)+kfv′(x)fu(x)+kfv′(1)kfu′(x)
维护 f u ( 1 ) , k f u ′ ( 1 ) f_u(1),kf_u'(1) fu(1),kfu′(1) 就可以快速转移 -
第三问
同样,我们令 F ( S ) = ∑ T 1 , T 2 [ T 1 ∩ T 2 = S ] , G ( S ) = ∑ T 1 , T 2 [ S ⊆ T 1 ∩ T 2 ] F(S)=\sum_{T1,T2}[T1\cap T2=S],G(S)=\sum_{T1,T2}[S\subseteq T1\cap T2] F(S)=∑T1,T2[T1∩T2=S],G(S)=∑T1,T2[S⊆T1∩T2]
那么 G ( S ) G(S) G(S) 有快速计算的方法: G ( S ) = ( n k − 2 ∏ a i ) 2 G(S)=(n^{k-2}\prod a_i)^2 G(S)=(nk−2∏ai)2
A n s = ∑ T ( 1 y − 1 ) ∣ T ∣ G ( T ) = ∑ T ( 1 y − 1 ) ∣ T ∣ ( n n − ∣ T ∣ − 2 ∏ i = 1 n − ∣ T ∣ a i ) 2 = ( 1 y − 1 ) n n 4 ∑ T ∏ i = 1 n − ∣ T ∣ ( a i ∗ n ) 2 1 y − 1 ( y ≠ 1 ) Ans=\sum_{T}(\frac{1}{y}-1)^{|T|}G(T)\\ =\sum_{T}(\frac{1}{y}-1)^{|T|}(n^{n-|T|-2}\prod_{i=1}^{n-|T|}a_i)^2\\=\frac{(\frac{1}{y}-1)^n}{n^4}\sum_{T}\prod_{i=1}^{n-|T|}\frac{(a_i*n)^2}{\frac{1}{y}-1}(y\neq 1) Ans=T∑(y1−1)∣T∣G(T)=T∑(y1−1)∣T∣(nn−∣T∣−2i=1∏n−∣T∣ai)2=n4(y1−1)nT∑i=1∏n−∣T∣y1−1(ai∗n)2(y=1)
枚举 T T T 的本质是在枚举森林,那么我们搞出每棵树的 E G F EGF EGF 后 e x p exp exp
F ( x ) = ∑ i = 1 i i − 2 ∗ i 2 k ∗ x i i ! F(x)=\sum_{i=1}i^{i-2}*i^2k*\frac{x^i}{i!} F(x)=∑i=1ii−2∗i2k∗i!xi,多项式全家桶!完结撒花!
#include<bits/stdc++.h>
#define cs const
#define pb push_back
#define poly vector<int>
using namespace std;
typedef pair<int,int> pi;
typedef long long ll;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) as=mul(as,a); return as; }
void Add(int &a, int b){ a = add(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
void Dec(int &a, int b){ a = dec(a, b); }
int inv(int a){ return ksm(a,Mod-2); }
int sgn(int a){ return a & 1 ? Mod - 1 : 1; }
int sqr(int a){ return mul(a, a); }
cs int N = 1e5 + 50, K = 18, M = 1 << K | 5;
int n, y, op, pw[M], Coef;
int fac[M], ifac[M], iv[M];
void fac_init(){
fac[0]=fac[1]=ifac[0]=ifac[1]=iv[0]=iv[1]=1;
for(int i=2; i<=(1<<K); i++) fac[i]=mul(fac[i-1],i);
for(int i=2; i<=(1<<K); i++) iv[i]=mul(Mod-Mod/i,iv[Mod%i]);
for(int i=2; i<=(1<<K); i++) ifac[i]=mul(ifac[i-1], iv[i]);
pw[0]=1; for(int i=1; i<=n; i++) pw[i]=mul(pw[i-1],y);
}
namespace Subtask0{
map<pi, bool> mp;
void work(){
for(int i=1; i<n; i++){
int x, y; scanf("%d%d",&x,&y);
mp[pi(x,y)]=true; mp[pi(y,x)]=true;
}
int c = 0;
for(int i=1; i<n; i++){
int x, y; scanf("%d%d",&x,&y);
if(mp.count(pi(x,y))) ++c;
} cout << pw[n-c];
}
}
namespace Subtask1{
vector<int> G[N];
int f[N], g[N], k;
void dp(int u, int fa){
f[u]=1; g[u]=k;
for(int v:G[u]) if(v^fa){
dp(v,u); int coe=add(g[v],f[v]); Mul(g[u],coe);
Add(g[u],mul(f[u],g[v])); Mul(f[u],coe);
}
}
void work(){
for(int i=1; i<n; i++){
int x, y; scanf("%d%d",&x,&y);
G[x].pb(y); G[y].pb(x);
} k = mul(n,inv(dec(inv(y),1))); dp(1,0);
cout<<mul(mul(Coef,g[1]),mul(ksm(dec(inv(y),1),n),sqr(inv(n))));
}
}
namespace Subtask2{
poly w[K+1], rev; int up, bit;
// void output(poly a){ for(int i=0; i<a.size(); i++) cout<<a[i]<<" "; puts(""); }
void NTT_init(){
for(int i=1; i<=K; i++) w[i].resize(1<<(i-1));
int wn=ksm(3,(Mod-1)/(1<<K)); w[K][0]=1;
for(int i=1; i<(1<<(K-1)); i++) w[K][i]=mul(w[K][i-1],wn);
for(int i=K-1;i;i--) for(int j=0;j<(1<<(i-1)); j++) w[i][j]=w[i+1][j<<1];
}
void init(int deg){
up=1, bit=0; while(up<deg) up<<=1,++bit; rev.resize(up);
for(int i=0; i<up; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void NTT(poly &a, int typ=1){
for(int i=0; i<up; i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int i=1,l=1; i<up; i<<=1,++l)
for(int j=0; j<up; j+=(i<<1))
for(int k=0; k<i; k++){
int x=a[k+j], y=mul(w[l][k],a[k+j+i]);
a[k+j]=add(x,y); a[k+j+i]=dec(x,y);
}
if(typ==-1){
reverse(a.begin()+1,a.end());
for(int i=0; i<up; i++) Mul(a[i],iv[up]);
}
}
poly operator * (poly a, poly b){
int deg=a.size()+b.size()-1; init(deg);
a.resize(up); b.resize(up); NTT(a); NTT(b);
for(int i=0; i<up; i++) Mul(a[i],b[i]); NTT(a,-1);
a.resize(deg); return a;
}
poly inv(poly f, int lim){
poly b(1,::inv(f[0])),c;
for(int deg=4; deg<(lim<<2); deg<<=1){
c.resize(deg>>1);
for(int i=0; i<(deg>>1); i++) c[i]=i<(int)f.size()?f[i]:0;
init(deg); c.resize(up); b.resize(up); NTT(c); NTT(b);
for(int i=0; i<up; i++) Mul(b[i],dec(2,mul(b[i],c[i])));
NTT(b,-1); b.resize(deg>>1);
} b.resize(lim); return b;
}
poly integ(poly f){
f.pb(0); for(int i=f.size()-1;i;i--)
f[i]=mul(f[i-1],iv[i]);
f[0]=0; return f;
}
poly deriv(poly f){
for(int i=1; i<(int)f.size(); i++)
f[i-1]=mul(i,f[i]);
f.pop_back(); return f;
}
poly ln(poly f, int deg){
f=integ(deriv(f)*inv(f,deg));
f.resize(deg); return f;
}
poly exp(poly f, int lim){
poly c, b(1,1);
for(int deg=2; deg<(lim<<1); deg<<=1){
c=ln(b,deg);
for(int j=0; j<deg; j++) c[j]=dec(j<(int)f.size()?f[j]:0,c[j]);
Add(c[0],1); b=b*c; b.resize(deg);
} b.resize(lim); return b;
}
void work(){
NTT_init(); int k=mul(sqr(n),::inv(dec(::inv(y),1)));
poly f(n+1,0);
for(int i=1; i<=n; i++) f[i]=mul(mul(k,ifac[i]),ksm(i,i));
poly g=exp(f,n+1); int coe=mul(fac[n],g[n]);
cout<<mul(mul(Coef,coe),mul(ksm(dec(::inv(y),1),n),::inv(sqr(sqr(n)))));
}
}
int main(){
scanf("%d%d%d",&n,&y,&op);
if(y==1){ cout<<ksm(n,(n-2)*op); return 0; }
fac_init(); Coef=pw[n];
if(op==0){ Subtask0::work(); return 0; }
if(op==1){ Subtask1::work(); return 0; }
if(op==2){ Subtask2::work(); return 0; }
}