CF1707D Partial Virtual Trees
CF1707D Partial Virtual Trees
注意到
具体地,令
考虑
显然的二项式反演形式,可知
回顾虚树的性质:称一个点被点亮当且仅当它为虚树关键点,若
笔者一开始想设
考虑转移,分
容易前缀和优化至
对于后者,枚举
改变求和顺序,预处理前后缀积从而预处理
同样
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 2e3 + 5;
int n, mod, f[N][N], s[N][N], g[N][N];
int F[N], C[N][N];
vector<int> e[N], son[N];
void dfs(int id, int ff) {
f[id][0] = s[id][0] = 1;
for(int it : e[id]) {
if(it == ff) continue;
son[id].push_back(it);
dfs(it, id);
}
for(int k = 0; k <= n; k++) {
int prod = 1;
for(int it : son[id]) prod = 1ll * prod * s[it][k] % mod;
static int pre[N], suf[N];
int L = son[id].size();
pre[0] = suf[L + 1] = 1;
for(int i = 1; i <= L; i++) {
pre[i] = 1ll * pre[i - 1] * s[son[id][i - 1]][k] % mod;
}
for(int i = L; i; i--) {
suf[i] = 1ll * suf[i + 1] * s[son[id][i - 1]][k] % mod;
g[son[id][i - 1]][k] = 1ll * pre[i - 1] * suf[i + 1] % mod;
}
}
for(int it : son[id])
for(int k = 1; k <= n; k++)
add(g[it][k], g[it][k - 1]);
for(int k = 1; k <= n; k++) {
int prod = 1;
for(int it : son[id]) prod = 1ll * prod * s[it][k] % mod;
add(f[id][k], prod);
for(int it : son[id]) {
int coef = f[it][k];
coef = 1ll * coef * g[it][k - 1] % mod;
add(f[id][k], coef);
}
}
for(int i = 1; i <= n; i++) {
s[id][i] = s[id][i - 1];
add(s[id][i], f[id][i]);
}
}
void solve() {
cin >> n >> mod;
for(int i = 0; i <= n; i++)
for(int j = 0; j <= i; j++) {
if(!j) C[i][j] = 1;
else C[i][j] = C[i - 1][j - 1], add(C[i][j], C[i - 1][j]);
}
for(int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1, 0);
for(int i = 1; i < n; i++) {
F[i] = 1;
for(int it : son[1]) F[i] = 1ll * F[i] * s[it][i - 1] % mod;
}
for(int i = 1; i < n; i++) {
int ans = 0;
for(int j = 1; j <= i; j++) {
int coef = 1ll * C[i][j] * F[j] % mod;
if(i - j & 1) add(ans, mod - coef);
else add(ans, coef);
}
cout << ans << " ";
}
cout << endl;
}
int main() {
int T = 1;
while(T--) solve();
return 0;
}