hdu

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5909
思路:相当于求树上某个连通块异或和为x的有多少个,很容易想到dp,先将无根树转换为有根树,dp[u][i]表示以u为根节点的子树异或和为i的方案数,然后向上合并,合并过程中父节点必选,跟子节点的方案进行卷积,用fwt加速卷积过程即可。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

using namespace std;

const int mod = 1e9 + 7;
const int rev = (mod + 1) >> 1;
const int maxn = 1 << 12;
typedef long long ll;
ll a[maxn], b[maxn], c[maxn];
int n, m;
int T;
ll v[maxn];

vector<int> G[maxn];
ll dp[1010][1 << 12];

inline ll (int x, int y){
x += y;
return x >= mod ? x - mod : x;
}

inline ll sub(int x, int y){
x -= y;
return x < 0 ? x + mod : x;
}

void fwt(ll a[], int n) {
for (int i = 1; i < n; i <<= 1){
for (int p = i << 1, j = 0; j < n; j += p) {
for (int k = 0; k < i; k++) {
int x = a[j + k], y = a[j + k + i];
a[j + k] = add(x, y), a[j + k + i] = sub(x, y);
}
}
}
}

void ufwt(ll a[], int n) {
for (int i = 1; i < n; i <<= 1) {
for (int p = i << 1, j = 0; j < n; j += p) {
for (int k = 0; k < i; k++) {
int x = a[j + k], y = a[j + k + i];
a[j + k] = 1ll * (x + y) * rev % mod, a[j + k + i] = 1ll * (x - y + mod) * rev % mod;
}
}
}
}

void solve(ll a[], ll b[], ll c[]){
fwt(a, m);
fwt(b, m);
for(int i = 0; i < m; i++) c[i] = 1ll * a[i] * b[i] % mod;
ufwt(a, m);
ufwt(b, m);
ufwt(c, m);
}

void dfs(int u, int f){
dp[u][v[u]] = 1;
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i];
if(v == f) continue;
dfs(v, u);
memcpy(a, dp[u], sizeof(dp[u]));
memcpy(b, dp[v], sizeof(dp[v]));
solve(a, b, c);
for(int j = 0; j < m; j++) dp[u][j] = add(dp[u][j], c[j]);
}
}

int main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> T;
while(T--){
cin >> n >> m;
for(int i = 1; i <= n; i++) G[i].clear(), cin >> v[i];
memset(dp, 0, sizeof(dp));
for(int i = 1; i < n; i++){
int u, v;
cin >> u >> v;
G[u].emplace_back(v);
G[v].emplace_back(u);
}
dfs(1, 0);
for(int i = 0; i < m; i++){
ll res = 0;
for(int j = 1; j <= n; j++) res = add(res, dp[j][i]);
cout << res << (i == m - 1 ? 'n' : ' ');
}
}
return 0;
}