他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画 nn 个“点”,并用 n-1n−1 条“边”把这 nn 个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是 33 的倍数,则判聪聪赢,否则可可赢。
usingnamespace std; using ll=longlong; constint XN=2010;
vector<int> g[XN]; int dfn[XN],sz[XN],tick=0; int re[XN]; int vis[XN]; int wage[XN];
int m; int square; intdfs(int u,int fa){ sz[u] = 1; dfn[u] = ++tick; re[tick] = u; for (auto v:g[u]) { if (vis[v] || v==fa)continue; sz[u] += dfs(v, u); } return sz[u]; } int SZ; int maxsz[XN],root=0; voidgetroot(int u,int fa){ sz[u] = 1; maxsz[u] = 0;
for (auto v:g[u]) { if (vis[v] || v == fa)continue; getroot(v, u); sz[u] += sz[v]; maxsz[u] = max(maxsz[u], sz[v]); } maxsz[u] = max(maxsz[u], SZ - maxsz[u]); if (root == 0 || maxsz[u] < maxsz[root])root = u; }
constint MOD=1000000007; intM(int &x){ return x %= MOD; }
int f[XN][XN],f2[XN][XN]; intcal(){ //默认选中root int res = 0; for (int i = 0; i <= tick + 1; i++) { memset(f[i], 0, sizeof(f[i])); memset(f2[i], 0, sizeof(f2[i])); } f[tick + 1][1] = 1; for (int i = tick; i >= 1; i--) { int w = wage[re[i]]; for (int j = 1; j <= min(m / w, square); j++) { int to = w * j; if (to <= square)M(f[i][to] += f[i + 1][j]); elseM(f2[i][m / to] += f[i + 1][j]); } for (int j = w; j <= square; j++) { M(f2[i][j / w] += f2[i + 1][j]); } //不选j,那么要跳过整个子树 for (int j = 1; j <= square; j++)M(f[i][j] += f[i + sz[re[i]]][j]); for (int j = 1; j <= square; j++)M(f2[i][j] += f2[i + sz[re[i]]][j]); } for (int i = 1; i <= square; i++)M(res += f[1][i]); for (int i = 1; i <= square; i++)M(res += f2[1][i]); //去掉不选root的情况 res--; returnM(res += MOD); } int ans=0; voidsolve(int u){ vis[u] = 1; tick = 0; dfs(u, 0); M(ans += cal()); for (auto v:g[u]) { if (vis[v])continue; SZ = sz[v]; root = 0; getroot(v, 0); solve(root); } }
intmain(){ int kase; cin >> kase; while (kase--) { int n; cin >> n >> m; square = sqrt(m);
for (int i = 1; i <= n; i++)g[i].clear(); memset(vis,0,sizeof(vis)); tick = 0; ans = 0;
for (int i = 1; i <= n; i++)cin >> wage[i];
for (int i = 1; i <= n - 1; i++) { int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u); } root = 0; SZ = n; getroot(1, 0); solve(root); cout << ans << endl; } }