花の塔
君が持ってきた漫画
くれた知らない名前のお花
今日はまだ来ないかな?
初めての感情知ってしまった
窓に飾った絵画をなぞってひとりで宇宙を旅して
それだけでいいはずだったのに
君の手を握ってしまったら
孤独を知らないこの街には
もう二度と帰ってくることはできないのでしょう
君が手を差し伸べた 光で影が生まれる
歌って聞かせて この話の続き
連れて行って見たことない星まで
誰の手も声も届かない
高く聳え立った塔の上へ
飛ばすフウセンカズラ
僕は君に笑って欲しいんだ
満たされない穴は惰性の会話や澄ましたポーズで
これまでは埋めてきたけど
退屈な日々を蹴散らして
君と二人でこの街中を泳げたら
それはどれだけ素敵なことでしょう?
出したことないほど大きな声でやっと君に伝わる
歪なくらいがさ きっとちょうどいいね
世界の端と端を結んで
窓に飾った絵画をなぞってひとりで宇宙を旅して
それだけでも不自由ないけど
僕は選んでみたいの
高鳴る心 謎だらけの空を
安全なループを今、書き換えて!
君の手を握ってしまったら
孤独を知らないこの街にはもう二度と
帰ってくることはできないのでしょう
いくらでも迷いながら光も影も見に行こう
歌って聞かせてこの話の続き
連れて行って見たことない星まで
世界の端と端を結んで
当然只有 \(op=1\)
有容斥做法,下次说,这里主要讲 jijidawang 的好做法。
一下称第一棵树(已知树)为 A,第二棵(未知树)为 B。
首先发现 B 的贡献只和其是否对应 A 的边有关,所以根据其是否是 A 的边将 B 划分成连通块。
设连通块数为 \(k\),则一种树贡献为 \(y^k\)
考虑将 \(k\) 个连通块拼成树的方案为 \(n^{k-2}\prod s_i\) 其中 \(s_i\) 为连通块大小。
但是这样如果用树边连接有拼重的,考虑新设一个贡献 \(v\) 使答案正确。
枚举树边的连接个数,对于一种树贡献是 \(\sum\limits_{i=0}^{n-k}\dbinom{n-k}{i}v^{k+i}\)。通过二项式定理得 \(v^k(1+v)^{n-k}\)
将 \((1+v)^n\) 提出来,最后在除上,联立 \(v^k(1+v)^{n-k}=y^k\) 解得 \(v=\frac{y}{1-y}\)
所以现在就是求:
\[\frac{\sum v^kn^{k-2}\prod s_i}{(1+v)^n} \]简单化简一下就是:
\[\frac{(1-y)^n}{n^2}\sum v^kn^k\prod s_i \]前面的显然整,后面已经可以 \(n^2\) dp 做了。
考虑继续推:
\[\frac{(1-y)^n}{n^2}\sum \prod s_inv \]发现后面相当于在每个联通块里选个点做出 \(nv\) 的贡献,最后求和,设 \(dp_{i,0/1}\) 表示 \(i\) 为根是否已经选了点,可以省掉枚举 \(k\),做到 \(O(n)\)。
Code
#include<bits/stdc++.h>
using namespace std;
using llt=long long;
using llf=long double;
using ull=unsigned long long;
#define endl '\n'
#ifdef LOCAL
FILE *InFile=freopen("in_out/in.in","r",stdin),*OutFile=freopen("in_out/out.out","w",stdout);
#else
FILE *InFile=stdin,*OutFile=stdout;
#endif
const int N=1e5+3,MOD=998244353;
struct Gph{
int hd[N],nt[N<<1],to[N<<1],tot=1;
void Add(int u,int v){to[++tot]=v,nt[tot]=hd[u],hd[u]=tot;}
void ADD(int u,int v){Add(u,v),Add(v,u);}
#define For_to(i,u,v,g) for(int i=g.hd[u],v=g.to[i];i;i=g.nt[i],v=g.to[i])
}g;
int Fpw(int a,int b){
int ans=1;
while(b){
if(b&1) ans=1ll*ans*a%MOD;
a=1ll*a*a%MOD,b>>=1;
}
return ans;
}
int Inv(int a){return Fpw(a,MOD-2);}
int n,y,v; ull dp[N][2];
void Dp(int u,int f){
dp[u][0]=1,dp[u][1]=1ll*v*n%MOD;
For_to(i,u,v,g) if(v!=f){
Dp(v,u);
dp[u][1]=dp[v][0]*dp[u][1]%MOD+dp[v][1]*dp[u][0]%MOD+dp[v][1]*dp[u][1]%MOD;
dp[u][0]=dp[v][0]*dp[u][0]%MOD+dp[v][1]*dp[u][0]%MOD;
}
}
int main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>y;
if(y==1) return cout<<Fpw(n,n-2),0;
for(int i=1;i<n;++i){int u,v; cin>>u>>v; g.ADD(u,v);}
v=1ll*y*Inv(1-y+MOD)%MOD; Dp(1,0);
cout<<dp[1][1]*(Fpw(1-y,n)+MOD)%MOD*Inv(1ll*n*n%MOD)%MOD;
}