We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
参考:
这道题难点在于如何用乘法原理计算每个路径的个数。我一开始打算用后序遍历来做,但后序遍历用乘法无法计算一条直路径的满足条件个数,所以按照正常逻辑应该用类似染色的思想来做,也就是如下的以质数节点为中心dfs来做。
乘法原理:循环累加过程中,可以用过当前个数curCnt * preSum来累计计算路径。
贴一个灵神的做法:
class Solution { private final static int MX = (int) 1e5; private final static boolean[] np = new boolean[MX + 1]; // 质数=false 非质数=true static { np[1] = true; for (int i = 2; i * i <= MX; i++) { if (!np[i]) { for (int j = i * i; j <= MX; j += i) { np[j] = true; } } } } public long countPaths(int n, int[][] edges) { List<Integer>[] g = new ArrayList[n + 1]; Arrays.setAll(g, e -> new ArrayList<>()); for (var e : edges) { int x = e[0], y = e[1]; g[x].add(y); g[y].add(x); } long ans = 0; int[] size = new int[n + 1]; var nodes = new ArrayList<Integer>(); for (int x = 1; x <= n; x++) { if (np[x]) { // 跳过非质数 continue; } int sum = 0; for (int y : g[x]) { // 质数 x 把这棵树分成了若干个连通块 if (!np[y]) { continue; } if (size[y] == 0) { // 尚未计算过 nodes.clear(); dfs(y, -1, g, nodes); // 遍历 y 所在连通块,在不经过质数的前提下,统计有多少个非质数 for (int z : nodes) { size[z] = nodes.size(); } } // 这 size[y] 个非质数与之前遍历到的 sum 个非质数,两两之间的路径只包含质数 x ans += (long) size[y] * sum; sum += size[y]; } ans += sum; // 从 x 出发的路径 } return ans; } private void dfs(int x, int fa, List<Integer>[] g, List<Integer> nodes) { nodes.add(x); for (int y : g[x]) { if (y != fa && np[y]) { dfs(y, x, g, nodes); } } } }
那么,根据这种染色的思想,可以用并查集来做,因为连通块之间都是被质数节点割裂开的,所以我们可以union两个非质数节点,然后再遍历质数节点用乘法原理计算。
class PrimeTable { private final boolean[] prime; public PrimeTable(int n) { prime = new boolean[n + 1]; Arrays.fill(prime, true); prime[0] = false; prime[1] = false; for (int i = 2; i <= n; ++i) { if (prime[i]) { for (int j = i + i; j <= n; j += i) { prime[j] = false; } } } } public boolean isPrime(int x) { return prime[x]; } } class UnionFind { private final int[] p; private final int[] size; public UnionFind(int n) { p = new int[n]; size = new int[n]; for (int i = 0; i < n; ++i) { p[i] = i; size[i] = 1; } } public int find(int x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; } public boolean union(int a, int b) { int pa = find(a), pb = find(b); if (pa == pb) { return false; } if (size[pa] > size[pb]) { p[pb] = pa; size[pa] += size[pb]; } else { p[pa] = pb; size[pb] += size[pa]; } return true; } public int size(int x) { return size[find(x)]; } } class Solution { private static final PrimeTable PT = new PrimeTable(100010); public long countPaths(int n, int[][] edges) { List<Integer>[] g = new List[n + 1]; Arrays.setAll(g, i -> new ArrayList<>()); UnionFind uf = new UnionFind(n + 1); for (int[] e : edges) { int u = e[0], v = e[1]; g[u].add(v); g[v].add(u); if (!PT.isPrime(u) && !PT.isPrime(v)) { uf.union(u, v); } } long ans = 0; for (int i = 1; i <= n; ++i) { if (PT.isPrime(i)) { long t = 0; for (int j : g[i]) { if (!PT.isPrime(j)) { long cnt = uf.size(j); ans += cnt; ans += cnt * t; t += cnt; } } } } return ans; } }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
2867. Count Valid Paths in a Tree
参考:
这道题难点在于如何用乘法原理计算每个路径的个数。我一开始打算用后序遍历来做,但后序遍历用乘法无法计算一条直路径的满足条件个数,所以按照正常逻辑应该用类似染色的思想来做,也就是如下的以质数节点为中心dfs来做。
乘法原理:循环累加过程中,可以用过当前个数curCnt * preSum来累计计算路径。
贴一个灵神的做法:
那么,根据这种染色的思想,可以用并查集来做,因为连通块之间都是被质数节点割裂开的,所以我们可以union两个非质数节点,然后再遍历质数节点用乘法原理计算。
The text was updated successfully, but these errors were encountered: