- 考慮\(\prod s[i]\)的組合意義:就是在每個連通塊內選一個點的方案數
- 應用鏈式前向星存圖時,應當捨棄“0-1”變換,從2號邊開始編號【對於其他情況,也應儘量避免從0開始編號】
- 列舉子樹大小DP是O(n^2)的,但如果有m的限制,可以證明時間複雜度降至O(nm)
- 因為出點和入點未必相同,所以不能簡單地把連通塊大小相乘;但相信最後的結果是美的,可以大膽猜想把m+1換成n
- 加法式列舉的好處在於,保證了兩邊都是合法的,避免了複雜度的錯誤
點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
vector<int>a[50005];
int s[50005],n,m;
const int mod=998244353;
long long f[50005][105][2],g[105][2];
int power(int n,int p)
{
if(p==0)
{
return 1;
}
long long tmp=power(n,p/2);
if(p%2==1)
{
return tmp*tmp%mod*n%mod;
}
return tmp*tmp%mod;
}
void dp(int n1)
{
s[n1]=1;
f[n1][0][0]=1;
f[n1][0][1]=1;
for(int i=0;i<a[n1].size();i++)
{
if(!s[a[n1][i]])
{
dp(a[n1][i]);
int k=a[n1][i];
memcpy(g,f[n1],sizeof(f[n1]));
memset(f[n1],0,sizeof(f[n1]));
for(int j=0;j<=min(s[n1]-1,m);j++)
{
for(int l=0;l<=min(s[k]-1,m);l++)
{
if(j+l>m)
{
break;
}
(f[n1][j+l][0]+=(g[j][0]*f[k][l][0]%mod))%=mod;
(f[n1][j+l][1]+=(g[j][1]*f[k][l][0]%mod+g[j][0]*f[k][l][1]%mod))%=mod;
if(j+l+1<=m)
{
(f[n1][j+l+1][0]+=(g[j][0]*f[k][l][1]%mod))%=mod;
(f[n1][j+l+1][1]+=(g[j][1]*f[k][l][1]%mod))%=mod;
}
}
}
s[n1]+=s[a[n1][i]];
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
dp(1);
cout<<f[1][m][1]*power(n,m-1)%mod<<endl;
return 0;
}