其实省选在四天前就已经结束了,但由于题目难度略大我到今天上午才补完所有题目……(捂脸逃)考场上很幸运,打完了所有我会写的部分分,最后Round1的110分 + Round2的70分,勉强算是没有被联赛day2的文件夹坑太多。。。
目前网上比较容易找到的题解似乎只有ydc教主的这份:http://ydc.blog.uoj.ac/blog/336,不过对于我这种水平的人来说这份题解还不是很好理解,那么我再来稍微补充一点更基础的内容吧。。
有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益。问收益最大值是多少。
其中$1 \leq N \leq 2000, 0 \leq K \leq N$。
分析.
从点和点的距离入手不太好分析……我在考场上想了一两个小时最后还是弃疗了,连暴力都没心情写,交了一份靠运气的贪心骗分。
其实呢……由于树上每一条边都是桥,我们可以从每一条边两端的黑白点数入手,也就是考虑每条边对答案造成的贡献。定义函数f(v, i)表示在v子树中,共将i个点染色后,能得到的“子树中所有点的父边的对答案的贡献之和”的最大值。这样每棵子树就成了一个可分割的子结构,就可以做树形背包了。
根据官方题解中给出的那种神奇的证明,这样做的时间复杂度是$O(N^2)$.
代码.
1 /***********************************************************************/
2 /**********************By Asm.Def-Wu Jiaxin*****************************/
3 /***********************************************************************/
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 using namespace std;
11 #define SetFile(x) ( freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout) );
12 #define UseFREAD
13 #ifdef UseFREAD
14 #define getc() *(file_ptr++)
15 #define FreadLenth 5000000
16 char CHARPOOL[FreadLenth], *file_ptr = CHARPOOL;
17 #else
18 #define getc() getchar()
19 #endif
20 #ifdef DEBUG
21 #include
22 timeb SysTp;
23 #endif
24 template<class T>inline void getd(T &x){
25 char ch = getc();bool neg = false;
26 while(!isdigit(ch) && ch != '-')ch = getc();
27 if(ch == '-')ch = getc(), neg = true;
28 x = ch - '0';
29 while(isdigit(ch = getc()))x = x * 10 - '0' + ch;
30 if(neg)x = -x;
31 }
32 /***********************************************************************/
33 const int maxn = 2003;
34 typedef long long LL;
35 #include
36 struct Edge{int to, w;};
37 vector adj[maxn];
38
39 LL f[maxn][maxn], S[maxn][maxn];
40 int N, K, size[maxn];
41
42 inline void UPD(LL &a, const LL &b){if(a < b)a = b;}
43
44 void dfs(int cur, int p, int w){
45 vector::iterator it;
46 int i, j, to;
47 size[cur] = 1;
48 for(it = adj[cur].begin();it != adj[cur].end();++it)if((to = (*it).to) != p){
49 dfs(to, cur, (*it).w);
50 for(i = min(size[cur], K);i >= 0;--i)for(j = min(size[to], K - i);j >= 0;--j)
51 UPD(S[cur][i + j], S[cur][i] + f[to][j]);
52 size[cur] += size[to];
53 }
54 for(i = size[cur];i >= 0;--i)
55 f[cur][i] = S[cur][i] + (LL)w * (i * (K - i) + (N - K - size[cur] + i) * (size[cur] - i));
56 }
57
58 inline void work(){
59 getd(N), getd(K);
60 int i, a, b, c;
61 for(i = 1;i < N;++i){
62 getd(a), getd(b), getd(c);
63 adj[a].push_back((Edge){b, c});
64 adj[b].push_back((Edge){a, c});
65 }
66 dfs(1, 0, 0);
67 printf("%lld\n", f[1][K]);
68 }
69
70 int main(){
71
72 #ifdef DEBUG
73 freopen("test.txt", "r", stdin);ftime(&SysTp);
74 size_t Begin_sec = SysTp.time, Begin_mill = SysTp.millitm;
75 #elif !defined ONLINE_JUDGE
76 SetFile(haoi2015_t1);
77 #endif
78
79 #ifdef UseFREAD
80 fread(file_ptr, 1, FreadLenth, stdin);
81 #endif
82
83 work();
84
85 #ifdef DEBUG
86 ftime(&SysTp);
87 printf("\n%.3lf sec \n", (SysTp.time - Begin_sec) + (SysTp.millitm - Begin_mill) / 1000.0);
88 #endif
89 return 0;
90 }
2 /**********************By Asm.Def-Wu Jiaxin*****************************/
3 /***********************************************************************/
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 using namespace std;
11 #define SetFile(x) ( freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout) );
12 #define UseFREAD
13 #ifdef UseFREAD
14 #define getc() *(file_ptr++)
15 #define FreadLenth 5000000
16 char CHARPOOL[FreadLenth], *file_ptr = CHARPOOL;
17 #else
18 #define getc() getchar()
19 #endif
20 #ifdef DEBUG
21 #include
22 timeb SysTp;
23 #endif
24 template<class T>inline void getd(T &x){
25 char ch = getc();bool neg = false;
26 while(!isdigit(ch) && ch != '-')ch = getc();
27 if(ch == '-')ch = getc(), neg = true;
28 x = ch - '0';
29 while(isdigit(ch = getc()))x = x * 10 - '0' + ch;
30 if(neg)x = -x;
31 }
32 /***********************************************************************/
33 const int maxn = 2003;
34 typedef long long LL;
35 #include
36 struct Edge{int to, w;};
37 vector adj[maxn];
38
39 LL f[maxn][maxn], S[maxn][maxn];
40 int N, K, size[maxn];
41
42 inline void UPD(LL &a, const LL &b){if(a < b)a = b;}
43
44 void dfs(int cur, int p, int w){
45 vector::iterator it;
46 int i, j, to;
47 size[cur] = 1;
48 for(it = adj[cur].begin();it != adj[cur].end();++it)if((to = (*it).to) != p){
49 dfs(to, cur, (*it).w);
50 for(i = min(size[cur], K);i >= 0;--i)for(j = min(size[to], K - i);j >= 0;--j)
51 UPD(S[cur][i + j], S[cur][i] + f[to][j]);
52 size[cur] += size[to];
53 }
54 for(i = size[cur];i >= 0;--i)
55 f[cur][i] = S[cur][i] + (LL)w * (i * (K - i) + (N - K - size[cur] + i) * (size[cur] - i));
56 }
57
58 inline void work(){
59 getd(N), getd(K);
60 int i, a, b, c;
61 for(i = 1;i < N;++i){
62 getd(a), getd(b), getd(c);
63 adj[a].push_back((Edge){b, c});
64 adj[b].push_back((Edge){a, c});
65 }
66 dfs(1, 0, 0);
67 printf("%lld\n", f[1][K]);
68 }
69
70 int main(){
71
72 #ifdef DEBUG
73 freopen("test.txt", "r", stdin);ftime(&SysTp);
74 size_t Begin_sec = SysTp.time, Begin_mill = SysTp.millitm;
75 #elif !defined ONLINE_JUDGE
76 SetFile(haoi2015_t1);
77 #endif
78
79 #ifdef UseFREAD
80 fread(file_ptr, 1, FreadLenth, stdin);
81 #endif
82
83 work();
84
85 #ifdef DEBUG
86 ftime(&SysTp);
87 printf("\n%.3lf sec \n", (SysTp.time - Begin_sec) + (SysTp.millitm - Begin_mill) / 1000.0);
88 #endif
89 return 0;
90 }