这题分两种情况考虑。
1、2*k<=n
这种情况需要中间一段(n-2*k+2长度)是一条直线,直线两端分别接k-1个点,那么这k-1个点形成一个星型,只要保证叶子节点比内部节点编号小就满足情况(直线编号小的那端)。dp搞定。
2、2*k>=n
这个中间一坨需要联通,然后看成一个球,向外也是星形射出,外面星形的部分和上面一样,球的部分可以全排列。
我代码具体做法:枚举一个点(假设是这个球编号最小的点),然后树形dp[i][left][right],表示第i个节点为根的子树,其中left个节点放前面,right个节点放后面(剩下那些就是球的一部分)。看上去是n^6,复杂度没那么高而且n=20
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <ctime> #include <cstring> using namespace std; class InducedSubgraphs { public: int getCount(vector<int> , vector<int> , int); }; ///////////////////////////////// long long pmod = 1000000009; long long C[55][55]; long long ba[55]; void pre() { int i, j; for (i = 0; i < 55; ++i) { C[i][0] = C[i][i] = 1; for (j = 1; j < i; ++j) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % pmod; } ba[0] = 1; for (i = 1; i < 55; ++i) ba[i] = ba[i - 1] * i % pmod; } ////////////////////////////////// int n, k; vector<int> nt[55]; int path[55]; bool flag1; int len2; bool dfs1(int i, int fa, int target, int id) { path[id] = i; if (i == target) { len2 = id + 1; if (id + 1 != n - 2 * k + 2) flag1 = false; for (int j = 1; j < len2 - 1; ++j) { if (nt[path[j]].size() != 2) flag1 = false; } return true; } for (int j = 0; j < nt[i].size(); ++j) { if (nt[i][j] == fa) continue; if (dfs1(nt[i][j], i, target, id + 1)) return true; } return false; } int cnt[55]; int dfscnt(int i, int fa) { int ret = 1; for (int j = 0; j < nt[i].size(); ++j) { if (nt[i][j] == fa) continue; ret += dfscnt(nt[i][j], i); } return cnt[i] = ret; } long long dfsans(int i, int fa) { long long ret = 1; int k = cnt[i] - 1; for (int j = 0; j < nt[i].size(); ++j) { if (nt[i][j] == fa) continue; ret = ret * C[k][cnt[nt[i][j]]] % pmod; ret = ret * dfsans(nt[i][j], i) % pmod; k -= cnt[nt[i][j]]; } return ret; } int gao1() { long long ans = 0; int i1, i2; for (i1 = 0; i1 < n; ++i1) { for (i2 = 0; i2 < n; ++i2) { if (i1 == i2) continue; flag1 = true; len2 = 0; dfs1(i1, -1, i2, 0); if (!flag1) continue; if (dfscnt(i1, path[1]) != k || dfscnt(i2, path[len2 - 2]) != k) continue; ans += dfsans(i1, path[1]) * dfsans(i2, path[len2 - 2]) % pmod; ans %= pmod; } } return ans; } int m; long long dp[50][30][30]; int dfs(int i, int fa) { int r, s, rr, ss; int cnt = 1; dp[i][0][0] = 1; for (int j = 0; j < nt[i].size(); ++j) { if (nt[i][j] == fa) continue; int k = nt[i][j]; cnt += dfs(k, i); for (r = m; r >= 0; --r) { for (s = m; s >= 0; --s) { if (dp[i][r][s] == 0) continue; for (rr = 0; rr + r <= m; ++rr) { for (ss = 0; ss + s <= m; ++ss) { if (dp[k][rr][ss] == 0) continue; if (rr == 0 && ss == 0) continue; dp[i][r + rr][s + ss] += dp[i][r][s] * dp[k][rr][ss] % pmod * C[r + rr][r] % pmod * C[s + ss][s] % pmod; dp[i][r + rr][s + ss] %= pmod; } } } } } dfscnt(i, fa); long long p = dfsans(i, fa); if (cnt <= m) { dp[i][cnt][0] += p; dp[i][cnt][0] %= pmod; dp[i][0][cnt] += p; dp[i][0][cnt] %= pmod; } return cnt; } int gao2() { int i; long long ans = 0; m = n - k; for (i = 0; i < n; ++i) { memset(dp, 0, sizeof(dp)); dfs(i, -1); ans += dp[i][m][m]; ans %= pmod; } return ans * ba[2 * k - n - 1] % pmod; } int InducedSubgraphs::getCount(vector<int> edge1, vector<int> edge2, int K) { int i; k = K; n = edge1.size() + 1; for (i = 0; i < n; ++i) nt[i].clear(); for (i = 0; i < n - 1; ++i) { nt[edge1[i]].push_back(edge2[i]); nt[edge2[i]].push_back(edge1[i]); } pre(); if (k == 1) return ba[n]; if (2 * k <= n) return gao1(); else return gao2(); }