- 考虑\(\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;
}