CF1917F:Construct Tree 题解
F:
题意:给你所有边的边权,问你能不能组成直径为d的一棵树。n,d<=2000。
Solution:
可以看出是个背包,然后不在直径上的那些边怎么安置呢。可以分成三种情况:
- 最长边加次长边大于d,直接No。
- 除去第一种情况下,如果直径包含最长边,那么未选入直径的边都可以接在最长边旁边,一定合法,做普通背包可求得。
- 不选最长边,这时最长边一定会接在中间的某个位置,需要满足这个位置两边都比它长。
可以看出这是个双背包问题,\(dp[i][j]\) 表示是否可以做到左边集合长 i ,右边集合长 j 。每次加入一条新边分为放入左边集合和放入右边集合,转移方式都非常简单。
省空间需要压缩掉枚举第几条边,然后注意倒着转移。压缩时间则是用bitset,因为不需要记录方案数,只需要记录是否可行。
这个dp矩阵的两维是对称的,开d个bitset,倒着枚举第一维,每次先横向转移,再纵向转移,就搞定了空间上的压缩:
bitset <N> b[N];
b[0][0] = 1;
for(int i=1;i<=n;i++) {
for(int j=d;j>=0;j--) {
b[j] |= (b[j]<<a[i]);
if(j>=a[i]) b[j] |= b[j-a[i]];
}
}
虽然是有史以来写的最烂的一次题解,不过既然你都做到这题了,这点东西你肯定一看就懂。qwq

浙公网安备 33010602011771号