题目传送门
题目大意
给定一个$n$个点的树$T = (G, V)$,每个点有一个正整数点权$a_{i}$。整棵树是第1级划分。定义第$i$级划分是将第$i - 1$级划分中的每个区域划分成至少两个新的区域,并且所有区域都是一个连通块,每个点在每一级中只属于一个区域,在同一级划分内每个区域内的点的点权和相等。一种划分方案包含它划分的每一级。两种划分方案不同当且仅当它们划分的级数不同,或者存在一个点在某一级中它们在两种划分方案中属于不同区域。
之前好像某次noip模拟考过类似的东西,但是当时没弄得清楚,感性理解了这个东西qwq。题解里涉及的大部分结论都被我猜到了,证这些花了半天,最后弃疗看题解。(为啥做了三道计数题都看了题解,果然我太菜了。)
注意
以下结论都在这样一些限制条件下讨论:
- 点权均为正整数。
- 每个点只属于一个区域。
- 如果涉及到有根树相关,默认以1为根。
设$s_{i}$表示以1为根时子树$i$内的点权和,$S = s_{1}$。
引理1 一棵$n$个点数的树,设$S = kS‘, k\in N_{+}, S‘ \in N$,则$\sum_{i = 1}^{n} [S‘\mid s_{i}] \leqslant k$
证明 当$k = 1$的时候,因为$a_{1} > 0$,所以它的子树内的所有点的$s_{i} < k$。
假设当$k \leqslant m - 1$时成立,考虑$k = m$的时候
- 若树内不存在一个点$i$,使得$s_{i} = xS‘, x \in N\wedge 1\leqslant x < m$,则$\sum_{i = 1}^{n} [S‘\mid s_{i}] = 1$,显然成立。
- 若树内存在一个点$i$,使得$s_{i} = xS‘, x \in N\wedge 1\leqslant x < m$,那么我们将它和它的父节点的边断开,把树分成两半部分,一半部分和为$xS‘$,另一部分和为$(m - x)S‘$。对于第一部分,它一定是以1为根的时候完整的一棵子树,把它删去后$i$的祖先的$s$值会减少,但是因为$S‘\mid s_{i}$,所以不会改变祖先的$s_{i}$对$S‘$取模后的剩余。因此可以将第一部分看成以$i$为根的树,第二部分看成以$1$为根的树,根据归纳假设易知,$\sum_{i = 1}^{n} [S‘\mid s_{i}] \leqslant m$。
所以定理得证。
不难发现,当$S‘$不是整数的时候,$\sum_{i = 1}^{n} [\frac{S‘}{s_{i}}\in Z] \leqslant k$也成立。因为我们将每个点的点权乘上$k$,这样新的$S‘$就是整数了,用引理1可得:
$\sum_{i = 1}^{n} [\frac{S‘}{s_{i}}\in Z] = \sum_{i = 1}^{n}[\frac{kS‘}{ks_{i}}\in Z]=\sum_{i = 1}^{n}[kS‘\mid ks_{i}]\leqslant k$
对于一个树$T = (V, E)$,设$f(T, d) = \sum_{v_{i} \in V} [d\mid s_{v_{i}}]$。
定理2 一棵$n$个点数的树$T$,能将它划分成$k$个点权和相等的连通块的充分必要条件是:
- $k\mid S$
- $f(T, \frac{S}{k}) = k$
证明 第一点的必要性显然,现在只考虑第二点。设$S = kS‘$。
必要性 我们考虑$k$个连通块,每个连通块的最浅点的$s$值一定是$S‘$的倍数。因为假设它不是$S‘$的倍数,那么由第一点的必要性可知它的子树内不能划分成若干联通块,剩下的点会被孤立,这样会使得划分方式不合法。
充分性 我们将所有满足$S‘ \mid s_{i}, i > 1$的点都和它的父节点把边断开,显然会产生$k$个连通块,现在证明这样一定满足条件:
-
- 因为点的权值都为正,所以不存在一个连通块的和为0或负数。
- 显然每个连通块的点权都是$S‘$的倍数
- 假设存在一个连通块的点权大于$S‘$,那么把它删去后会剩下若干个树$T_{1}, \cdots, T_{p}$,它们的点权和小于$(k - 1)S‘$,由引理1易证$\sum_{i = 1}^{p}f(T_{i}, S‘) < k - 1$。所以这个连通块内至少存在两个点它们的$s$值是$S‘$的倍数,这与构造的方案矛盾。所以不存在一个连通块的权值和大于$S‘$。
由以上三点可知对于每一个连通块的权值都是$S‘$。因此定理得证。
同时我们由证明过程也知道,满足$S‘ \mid s_{i}, i > 1$的点都必须和它的父节点把边断开,也就是说方案是唯一的。
也就是说:
推论3 一棵$n$个点数的树$T$,能将它划分成$k$个点权和相等的连通块的方案数要么是0,要么是1。
先考虑对于第2级划分,我们希望知道对于每一个$k, 1\leqslant k \leqslant n$,$f(T, \frac{S}{k})$的值。
根据定义有
$f(T, \frac{S}{k}) = \sum_{v_{i} \in V} [\frac{S}{k}\mid s_{v_{i}}]\\= \sum_{v_{i} \in V} [S\mid s_{v_{i}}k]\\= \sum_{v_{i} \in V} [\frac{S}{(S, s_{i})}\mid k]$
那么现在可以用一个简单dp在$O(n\log n)$内处理掉它。
考虑级数大于2的时候,不难发现以下结论:
定理4 一棵$n$个点数的树$T$,能够划分成2个分别包含$k_{1}, k_{2}\ \ (k_{1} < k_{2})$个区域的级别的充分必要条件是:
- $k_{1}\mid k_{2}, k_{2}\mid S$
- $f(T, \frac{S}{k_1}) = k_1 \wedge f(T, \frac{S}{k_2}) = k_2$
证明 必要性显然。
充分性 考虑我们将这个数划分成$k_{1}$个区域,每个区域是一个连通块,那么就是一棵树。设它们分别是$T_{1}, \cdots, T_{k_{1}}$。每一部分的和都是$\frac{S}{k_{1}}$,由第一点可知是$\frac{S}{k_{2}}$的倍数,因此分开后对$s_{i}$对$\frac{S}{k_{2}}$取模后的剩余无影响。由引理1可知$f(T_{i}, \frac{S}{k_{2}}) \leqslant \frac{k_2}{k_1}$,又因为$f(T, \frac{S}{k_2}) = k_2 = k_{1}\times \frac{k_{2}}{k_{1}}$,所以$f(T_{i}, \frac{S}{k_{2}}) = \frac{k_2}{k_1}$,由定理2可知每一区域都可以划分成$\frac{k_{2}}{k_{1}}$个新区域。
因此定理得证。
由推论3和定理4可知如果将划分成$k$个区域的方案看成一个点,满足$k_{1}, k_{2}\ \ (k_{1} < k_{2})$和定理4的两点的两个合法的一级划分,那么$k_{1}$向$k_{2}$连一条有向边,显然它构成了一个DAG。那么一个合法的划分方案对应从1开始的一条路径。现在就简单了,用$g_{i}$表示以$i$为路径结尾的路径条数,再做一次dp就完了。
最后来证一个可以压常数的结论,推广一下$f$,现在把它设成$f(T, d) = \sum_{v_{i} \in V} [\frac{s_{v_{i}}}{d} \in Z]$。
推论5 一棵$n$个点数的树$T$,设$S = kS‘, k\in N_{+}, k > 1, k\nmid S$,则$f(T, S‘) < k$
证明 考虑$k = 2$的时候,因为$k\nmid S$,所以只有$s_{1}$满足条件,$f(T, S‘) = 1 < 2$。
假设当$k \leqslant m - 1$的时候成立,考虑$k = m$的时候,
- 若不存在一个点$i, i > 1$使得$\frac{s_{i}}{S‘} \in Z$,那么$f(T, S‘) = 1 < m$。
- 若存在一个点$i, i > 1$使得$\frac{s_{i}}{S‘} \in Z$,那么我们把它和它的父节点的边断开,把树分成两棵树$T_{1}, T_{2}$,因为$\frac{s_{i}}{S‘}$的小数部分为0,所以对它的祖先$\frac{s_{j}}{S‘}$的小数部分没有影响,即不会改变它是否为整数。显然两部分的和都小于$mS‘$,所以由归纳假设可知当$k = m$时成立。
因此定理得证。
现在就不用判断$k$是否是$S$的约数了,只用判断$f(T, \frac{S}{k})$的值。
总时间复杂度$O(n\log n)$。
Code
1 /** 2 * Codeforces 3 * Problem#1034C 4 * Accepted 5 * Time: 717ms 6 * Memory: 19900k 7 */ 8 #include <bits/stdc++.h> 9 #ifndef WIN32 10 #define Auto "%lld" 11 #else 12 #define Auto "%I64d" 13 #endif 14 using namespace std; 15 typedef bool boolean; 16 #define ll long long 17 18 const int N = 1e6 + 5, M = 1e9 + 7; 19 20 ll gcd(ll a, ll b) { 21 return (b) ? (gcd(b, a % b)) : (a); 22 } 23 24 int add(int a, int b) { 25 return ((a += b) >= M) ? (a - M) : (a); 26 } 27 28 int n, res; 29 ll ss[N]; 30 int fa[N], f[N], g[N]; 31 32 int main() { 33 scanf("%d", &n); 34 for (int i = 1; i <= n; i++) 35 scanf(Auto, ss + i); 36 for (int i = 2; i <= n; i++) 37 scanf("%d", fa + i); 38 for (int i = n; i > 1; i--) 39 ss[fa[i]] += ss[i]; 40 ll S = ss[1]; 41 for (int i = 1; i <= n; i++) 42 if ((ss[i] = S / gcd(S, ss[i])) <= n) 43 f[ss[i]]++; 44 for (int i = n; i; i--) 45 for (int j = i << 1; j <= n; j += i) 46 f[j] += f[i]; 47 g[1] = 1; 48 for (int i = 1; i <= n; i++) 49 if (f[i] == i) { 50 res = add(res, g[i]); 51 for (int j = i << 1; j <= n; j += i) 52 g[j] = add(g[j], g[i]); 53 } 54 printf("%d\n", res); 55 return 0; 56 }
原文地址:https://www.cnblogs.com/yyf0309/p/9694235.html