QOJ7126. Control point 题解
题意描述
给定一颗 \(n\) 个节点的树,有 \(m\) 个节点是特殊节点,现在你需要选择一些点作为控制节点,使得任意一个特殊节点都能通过树上的至多 \(r\) 条边,到达至少一个控制节点,输出选择控制节点的方案数。
解题思路
直接做不好做,在树上选择一些节点为控制节点,\(d_i\) 表示点 \(i\) 与控制节点的距离,把其转换为序列,就会发现,每一种填数位的方案都与一种序列一一对应,于是便好做了。
在树上选择一些节点为控制节点,\(d_i\) 表示 \(i\) 个点,与控制节点最近的距离,把其转换为序列,就会发现,每一种填数位的方案都与一种序列一一对应,于是便好做了。
我们考虑每个点 \(u\) 它可以有哪些控制点影响,无非就是从儿子来的,或者从父亲来的,知道了这些就可以考虑DP。
状态设计
设计这样的DP状态\(f[u][k][0/1]\),表示在节点 \(u\) 填 \(k\),\(0/1\),是从父亲/儿子转移过来。
记 \(lim[u]\) 为 \(u\) 节点最远的可以被覆盖的距离,对于特殊节点, \(lim[u]=r\),否则 \(lim[u] = n\)。
初始状态
- \(f[u][0][1]=1\)
- \(\forall i\in[1,lim[u]],dp[u][i][0]=1\)
- 不合法的 \(f[u][i][0/1]=0\)
状态转移
\(g\) 是滚动数组
- \(f[u][i][0] \gets g[i][0]\times(f[v][i-1][0]+f[v][i][1] + f[v][i+1][1])\)
- \(f[u][i][1] \gets g[i][1]\times(f[v][i-1][0]+f[v][i-1][1]+f[v][i][1]+f[v][i+1][1])\)
- \(f[u][i][1] \gets g[i][0]\times f[v][i-1][1]\)
答案统计
\(ans = \sum_{i=1}^nf[1][i][1]\)
code:
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define out() (cout << "sb\n")
const int N = 2005, mod = 1e9 + 7;
int n, m, r, lim[N];
ll dp[N][N][2], g[N][2]; //dp[u][i][0/1]:当前位置 u,填的数是i,下一层是否有小于它的数(说明子树内有控制点)
vector<int> G[N];
void dfs(int u, int p) {
dp[u][0][1] = 1; //选做控制点,填0
for (int i = 1; i <= lim[u]; i++) dp[u][i][0] = 1; //不选
for (int &v : G[u]) {
if (v == p) continue;
dfs(v, u);
for (int i = 0; i <= lim[u]; i++)
g[i][0] = dp[u][i][0], g[i][1] = dp[u][i][1];
dp[u][0][1] = g[0][1] * (dp[v][0][1] + dp[v][1][0] + dp[v][1][1]) % mod;
for (int i = 1; i <= lim[u]; i++) {
dp[u][i][0] = g[i][0] * (dp[v][i][1] + dp[v][i + 1][1] + dp[v][i + 1][0]) % mod;
dp[u][i][1] = g[i][1] * (dp[v][i - 1][1] + dp[v][i][1] + dp[v][i + 1][0] + dp[v][i + 1][1]);
dp[u][i][1] = (dp[u][i][1] + g[i][0] * dp[v][i - 1][1]) % mod;
}
}
}
int main(){
//system("fc .out .out");
//freopen(".in", "r", stdin);
//freopen(".out", "w", stdout);
IOS;
cin >> n >> m >> r;
for (int i = 1; i <= n; i++) lim[i] = n;
for (int i = 1; i <= m; i++) {
int x;
cin >> x;
lim[x] = r;
}
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
ll ans = (m == 0);
for (int i = 0; i <= n; i++)
ans = (ans + dp[1][i][1]) % mod;
cout << ans << "\n";
return 0;
}

浙公网安备 33010602011771号