【题目链接】
【思路要点】
- 将所有点按照点权从大到小排序,依次加入树中。
- 以每一个新加入的点为根做树形背包,统计包含该点,且包含恰好\(K\)个被加入的点的联通块个数,将该数乘上新加入的点的权值,加入答案。
- 时间复杂度\(O((N-K)*N*K)\),实际上这个时间复杂度是不正确的,但在考场上笔者写了这个程序,通过了全部的数据,并且正解比较反人类,就不写了。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e3 + 5; const int P = 64123; template <typename T> void read(T &x) { int f = 1; x = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } struct info {unsigned val; int home; }; info tmp[MAXN]; bool indx[MAXN]; int n, k, w, size[MAXN]; unsigned val[MAXN], dp[MAXN][MAXN]; vector <int> a[MAXN]; void merge(unsigned *s, unsigned *t, int sn, int &tn) { static unsigned tmp[MAXN]; for (int i = 0; i <= tn; i++) tmp[i] = t[i]; for (int i = 0; i <= tn + sn; i++) t[i] = 0; for (register int i = 0; i <= sn && i <= k; i++) for (register int j = 0; j <= tn && i + j <= k; j++) t[i + j] = (t[i + j] + s[i] * tmp[j]) % P; tn += sn; } void work(int pos, int fa) { size[pos] = indx[pos]; for (int i = 0; i <= size[pos]; i++) dp[pos][i] = 0; dp[pos][indx[pos]]++; for (unsigned i = 0; i < a[pos].size(); i++) if (a[pos][i] != fa) { work(a[pos][i], pos); merge(dp[a[pos][i]], dp[pos], size[a[pos][i]], size[pos]); } dp[pos][0] = (dp[pos][0] + 1) % P; } void subtask() { static unsigned tmp[MAXN]; int s = 0, f = 0, tot = 0; unsigned ans = 0; for (int i = 1; i <= n; i++) if (a[i].size() == 1) s = i; for (int i = 1; i <= n; i++) { tmp[++tot] = val[s]; for (unsigned j = 0; j < a[s].size(); j++) if (a[s][j] != f) { f = s; s = a[s][j]; break; } } static priority_queue <unsigned, vector <unsigned>, greater <unsigned> > Heap; for (int i = 1; i <= n; i++) { while (!Heap.empty()) Heap.pop(); for (int j = i; j <= n; j++) { Heap.push(tmp[j]); if (Heap.size() > (unsigned) k) Heap.pop(); if (Heap.size() == (unsigned) k) ans = (ans + Heap.top()) % P; } } cout << ans << endl; } bool cmp(info a, info b) {return a.val > b.val; } int main() { read(n), read(k), read(w); for (int i = 1; i <= n; i++) read(val[i]), tmp[i] = (info) {val[i], i}; for (int i = 1; i <= n - 1; i++) { int x, y; read(x), read(y); a[x].push_back(y); a[y].push_back(x); } bool line = true; for (int i = 1; i <= n; i++) if (a[i].size() >= 3) line = false; if (line) { subtask(); return 0; } sort(tmp + 1, tmp + n + 1, cmp); unsigned ans = 0; for (int i = 1; i <= n; i++) { indx[tmp[i].home] = true; if (i >= k) { work(tmp[i].home, 0); ans = (ans + dp[tmp[i].home][k] * tmp[i].val) % P; } } cout << ans << endl; return 0; }