SNOI 2024 D1T1 题解
我现在发现我去年写的这东西太抽象了,所以我选择直接重写一遍,想看我发一堆无意义牢骚的可以看这里。
有一些 corner:关键点的
为方便叙述,我们令
注意到一条满足
我们关于上文“颜色的连通块”dp。设
我们仍然关于连通块整体转移:现在存在一条满足
根据这个做转移,时间复杂度
#include<iostream>
#include<vector>
#define pb push_back
const int p = 998244353;
int n, fl, k, rs, a[3050], f[3050], ct[3050];
std::vector <int> e[3050], o[3050];
inline void gr(std::vector<int> &vc, int x, int fa, int d){
(vc[d] += f[x]) %= p; for(auto v:e[x])
if(v != fa && a[v] == a[x]) gr(vc, v, x, d + 1);
}
inline void dp(std::vector<int> &vc, int x, int fa, int k, int d){
f[x] = 1ll * f[x] * (vc[d] + vc[d + (a[x] < k ? -1 : 1)]) % p;
for(auto v:e[x]) if(v != fa && a[v] == a[x]) dp(vc, v, x, k, d + 1);
}
inline void dfs(int x, int fa){
ct[a[x]] += a[x] != a[fa];
if(ct[a[x]] >= 2) return void(fl = 1);
for(auto v:e[x]) if(v != fa){
dfs(v, x); if(a[v] != a[x]){
std::vector<int>vc(n + 5);
gr(vc, v, x, 1); dp(vc, x, v, a[v], 1);
}
}
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);std::cout.tie(0);
int T; std::cin >> T; while(T--){
std::cin >> n >> k; rs = fl = 0;
for(int i = 1; i <= n; i++)
e[i].clear(), o[i].clear(), ct[i] = 0;
for(int i = 1, x, y; i < n; i++)
std::cin >> x >> y, e[x].pb(y), e[y].pb(x);
for(int i = 1; i <= n; i++)
std::cin >> a[i], o[a[i]].pb(i);
for(int i = 1; i <= n; i++) f[i] = 1;
dfs(1, 0); for(int i = 1; i <= k; i++)
if(!ct[i]) {fl = 1; break;}
if(fl){std::cout << 0 << '\n'; continue;}
for(auto v:o[a[1]]) (rs += f[v]) %= p;
std::cout << rs << '\n';
}
}