題面c++
思路:函數
函數f至關因而求一個點集f的直徑,有一個性質是若是這個點集有多個直徑必定相交於某一個點,或者一條邊的中心,因此咱們暴力枚舉重心,計算以某個點爲重心的點集對答案的貢獻。spa
具體實現的時候,咱們從一個重心開始深搜,計算其它點到這個點的距離。咱們如今假設計算以當前點爲重心,有多少個點集的直徑是i。首先,以前全部半徑小於i / 2的點隨便選了,假設有sum個,那前面的點有2 ^ sum種狀況。假設半徑是i / 2的點有cnt[i]個,那只有這些點纔可能構造出i的直徑,而且,這兩個點不能在一個連通塊中(把重心去掉後可能會造成若干個連通塊), 因此咱們枚舉每一個連通塊中半徑是i / 2的點數,此時假設其它連通塊中沒有點半徑是i / 2,減去這些狀況就能夠了。設計
代碼:blog
#include <bits/stdc++.h> #define LL long long using namespace std; const int maxn = 4010; const LL mod = 998244353; int head[maxn], Next[maxn * 2], ver[maxn * 2], tot; LL cnt[maxn], re[maxn][maxn], p[maxn], ans[maxn]; int n; void add(int x, int y) { ver[++tot] = y; Next[tot] = head[x]; head[x] = tot; } void dfs(int x, int fa, int deep, int dye) { if(x <= n) { cnt[deep]++; re[dye][deep]++; } for (int i = head[x]; i; i = Next[i]) { int y = ver[i]; if(y == fa) continue; dfs(y, x, deep + 1, dye); } } int main() { int x, y; scanf("%d", &n); for (int i = 1; i < n; i++) { scanf("%d%d", &x, &y); add(x, i + n), add(i + n, x), add(y, i + n), add(i + n, y); } p[0] = 1; for (int i = 1; i <= 2 * n - 1; i++) p[i] = (p[i - 1] * 2) % mod; for (int i = 1; i <= 2 * n - 1; i++) { int dye = 0; LL sum = 0; memset(cnt, 0, sizeof(cnt)); if(i <= n) { cnt[0]++; sum = 1; } for (int j = head[i]; j; j = Next[j]) { int y = ver[j]; dye++; memset(re[dye], 0, sizeof(re[dye])); dfs(y, i, 1, dye); } for (int j = 1; j < n; j++) { LL now = p[cnt[j]] - 1; for (int k = 1; k <= dye; k++) now = (now - (p[re[k][j]] - 1) + mod) % mod; ans[j] = (ans[j] + (now * p[sum]) % mod) % mod; sum += cnt[j]; } } for (int i = 1; i < n; i++) printf("%lld\n", ans[i]); }