合约数
借鉴了巨巨的代码,学会看数据量。
题解:预处理得到每个Val的所有合约数,因为最大的Val才10000。然后在DFS的过程中,对每个节点u,先减去已经存在的u的合约数个数,当回溯到这个节点u的时候,加上u的合约数的个数(子树里面的合约数)。
1 #pragma warning(disable:4996) 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 #define ll long long 8 using namespace std; 9 10 const int maxn = 20005; 11 const int mod = 1000000007; 12 13 vector<int> Tree[maxn], H[maxn]; 14 15 ll ans, F[maxn]; 16 int n, p, kase, cnt[maxn], val[maxn]; 17 bool prime[maxn], use[maxn]; 18 19 void Inite() { 20 21 memset(prime, 0, sizeof(prime)); 22 prime[0] = prime[1] = true; 23 24 for (int i = 2; i <= 100; i++) if (!prime[i]) { 25 for (int j = i * i; j <= 10000; j += i) { 26 prime[j] = true; 27 } 28 } 29 30 for (int i = 4; i <= 10000; i++) if (prime[i]) { 31 for (int j = 4; j <= i; j++) if (prime[j] && (i % j == 0)) { 32 H[i].push_back(j); 33 } 34 } 35 } 36 37 void DFS(int u) { 38 for (int i = 0; i < H[val[u]].size(); i++) F[u] -= cnt[H[val[u]][i]]; 39 cnt[val[u]]++; 40 for (int i = 0; i < Tree[u].size(); i++) { 41 int v = Tree[u][i]; 42 if (!use[v]) { 43 use[v] = 1; 44 DFS(v); 45 } 46 } 47 for (int i = 0; i < H[val[u]].size(); i++) F[u] += cnt[H[val[u]][i]]; 48 ans += 1LL * u * F[u]; 49 ans %= mod; 50 } 51 52 int main() 53 { 54 Inite(); 55 scanf("%d", &kase); 56 while (kase--) { 57 scanf("%d%d", &n, &p); 58 59 memset(F, 0, sizeof(F)); 60 memset(cnt, 0, sizeof(cnt)); 61 memset(use, 0, sizeof(use)); 62 63 use[p] = 1; 64 for (int i = 1; i <= n; i++) Tree[i].clear(); 65 66 for (int i = 2; i <= n; i++) { 67 int u, v; 68 scanf("%d%d", &u, &v); 69 Tree[u].push_back(v); 70 Tree[v].push_back(u); 71 } 72 for (int i = 1; i <= n; i++) { 73 scanf("%d", val + i); 74 } 75 76 ans = 0; 77 DFS(p); 78 printf("%lld\n", ans); 79 } 80 return 0; 81 }