首页 > 其他分享 >E1. PermuTree (easy version)

E1. PermuTree (easy version)

时间:2023-08-07 20:13:23浏览次数:60  
标签:limits cdot PermuTree 节点 leq int version E1 ldots

E1. PermuTree (easy version)

This is the easy version of the problem. The differences between the two versions are the constraint on $n$ and the time limit. You can make hacks only if both versions of the problem are solved.

You are given a tree with $n$ vertices rooted at vertex $1$.

For some permutation$^\dagger$ $a$ of length $n$, let $f(a)$ be the number of pairs of vertices $(u, v)$ such that $a_u < a_{\operatorname{lca}(u, v)} < a_v$. Here, $\operatorname{lca}(u,v)$ denotes the lowest common ancestor of vertices $u$ and $v$.

Find the maximum possible value of $f(a)$ over all permutations $a$ of length $n$.

$^\dagger$ A permutation of length $n$ is an array consisting of $n$ distinct integers from $1$ to $n$ in arbitrary order. For example, $[2,3,1,5,4]$ is a permutation, but $[1,2,2]$ is not a permutation ($2$ appears twice in the array), and $[1,3,4]$ is also not a permutation ($n=3$ but there is $4$ in the array).

Input

The first line contains a single integer $n$ ($2 \le n \le 5000$).

The second line contains $n - 1$ integers $p_2,p_3,\ldots,p_n$ ($1 \le p_i < i$) indicating that there is an edge between vertices $i$ and $p_i$.

Output

Output the maximum value of $f(a)$.

Examples

input

5
1 1 3 3

output

4

input

2
1

output

0

input

6
1 2 2 1 5

output

7

input

4
1 1 1

output

2

Note

The tree in the first test:

One possible optimal permutation $a$ is $[2, 1, 4, 5, 3]$ with $4$ suitable pairs of vertices:

$(2, 3)$, since $\operatorname{lca}(2, 3) = 1$ and $1 < 2 < 4$,
$(2, 4)$, since $\operatorname{lca}(2, 4) = 1$ and $1 < 2 < 5$,
$(2, 5)$, since $\operatorname{lca}(2, 5) = 1$ and $1 < 2 < 3$,
$(5, 4)$, since $\operatorname{lca}(5, 4) = 3$ and $3 < 4 < 5$.

The tree in the third test:

The tree in the fourth test:

 

解题思路

  对于所有合法的数对$(u, v)$,按照其最近公共祖先$\operatorname{lca}(u,v)$进分类可得到$n$类。将最近公共祖先固定,分别求当$\operatorname{lca}(u,v) = w$时,满足$a_u < a_w < a_v$的数对的最大数目。问题等价于考虑以$w$为根节点的子树,并且$u$和$v$分别在以$w$所有儿子所构成的不同子树中,满足合法数对的最大数量(当$w$没有儿子或只有一个儿子,那么不存在合法的数对,因为不等式不成立,或者是最近公共祖先不是$w$)。

  因此在固定了最近公共祖先为$w$后,假设节点$w$有$m$个儿子,那么我们只用关心在以其$m$个儿子所构成的各个子树中,有多少个节点满足$a_u < a_w$(那么剩下的节点自然满足大于$a_w$)。假设以第$i$个儿子为根的子树大小是$s_i$,并且有$b_i$$(0 \leq b_i \leq s_i)$个节点满足$a_u < a_w$,那么所有以$w$为最近公共祖先的合法数对的数量就是$$(s_1 - b_1) \cdot (0 + b_2 + \ldots + b_m) + (s_2 - b_2) \cdot (b_1 + 0 + \ldots + b_m) + \ldots + (s_m - b_m) \cdot (b_1 + b_2 + \ldots + 0)$$

  事实上对于任意的满足$0 \leq b_i \leq s_i$的$b_i$,都可以找到与之对应的排列$a$。先定义集合$L_x$表示往以$x$为根的子树中所有节点所表示的位置填入的数,集合的大小就是子树的大小。$m_i$表示节点$i$的儿子数量。构造的方法如下:

  1. 先从根节点$x=1$开始,此时$L_x = \{ 1, 2, \ldots, n \}$。
  2. 假设根节点为$x$,$x$的儿子分别为$y_1, \ldots, y_{m_x}$,$b_1, \ldots, b_{m_x}$对应的最优值是$c_1, \ldots, c_{m_x}$。$L_{y_1}, \ldots, L_{y_m}$均为空集。
  3. 对于从$1$到$m_x$的每一个$i$,依次从$L_x$中选出前$c_i$个最小的数放到$L_{y_i}$中,并从$L_x$中删除。
  4. 从$L_x$中选出最小的数作为$a_x$,并从$L_x$中删除。
  5. 对于从$1$到$m_x$的每一个$i$,依次从$L_x$中选出前$s_i - c_i$个最小的数放到$L_{y_i}$中,并从$L_x$中删除。
  6. 对于每一个儿子$y_1, \ldots, y_{m_x}$,重复上述过程,直到不存在儿子。

  我们现在要做的是最大化上述表达式的值。定义状态$f(i,j)$表示固定最近公共祖先$w$(以$w$为根的子树)后,考虑$u$和$v$在前$i$个儿子所构成的子树中,并且$\sum\limits_{k=1}^{i}{b_k} = j$,所合法数对的最大值。根据第$i$个子树中有多少个节点满足$a_u < a_w$来进行状态划分,定义$S_i = \sum\limits_{k=1}^{i}{s_k}$,状态转移方程为$$f(i,j) = \max\limits_{\max\{0, j - S_{i-1} \ \} \leq b_i \leq \min\{s_i, j\}} \left\{ f(i-1, j-b_i) + b_i \cdot \left( S_{i-1} - (j - b_i) \right) + (s_i - b_i) \cdot (j - b_i) \right\}$$

  其中限制$\max\{0, j - S_{i-1}\} \leq b_i \leq \min\{s_i, j\}$是根据不等式组$\begin{cases} 0 \leq b_i \leq s_i \\ 0 \leq j - b_i \leq S_{i - 1} \end{cases}$得到。$f(i-1, j-b_i)$则表示数对$(u,v)$均在前$i-1$个子树时所得到的最大数量。$b_i \cdot \left( S_{i-1} - (j - b_i) \right)$表示$u$在第$i$个子树,$v$在前$i-1$个子树的数对数量。$(s_i - b_i) \cdot (j - b_i)$表示$u$在前$i-1$个子树,$v$在第$i$个子树的数对数量。

  因此最近公共祖先为$w$的合法数对的最大数量就是$\max\limits_{0 \leq j \le S_m}{\left\{ f(m,j) \right\}}$。又因为以不同节点为最近公共祖先的合法数对的最大值是相互独立的,因此最终答案就是将分别求到的最大值累加,即$$\text{ans} = \sum\limits_{i=1}^{n}{\max\limits_{0 \leq j \le S_{m_i}}{\left\{ f(m_i,j) \right\}}}$$

  看上去总的时间复杂度好像是$O(n^3)$,实际上应该是$O(n^2)$,这里先贴代码,下面再补充证明。参考01背包的空间优化,这里也可以将$f(i,j)$优化为$f(j)$。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 5010;
 5 
 6 int head[N], e[N], ne[N], idx;
 7 int sz[N];
 8 int f[N];
 9 
10 void add(int v, int w) {
11     e[idx] = w, ne[idx] = head[v], head[v] = idx++;
12 }
13 
14 int dfs(int u) {
15     sz[u] = 1;
16     int ret = 0;
17     for (int i = head[u]; i != -1; i = ne[i]) {
18         ret += dfs(e[i]);
19         sz[u] += sz[e[i]];
20     }
21     memset(f, 0, sizeof(f));
22     for (int i = head[u], s = 0; i != -1; i = ne[i]) {
23         for (int j = s + sz[e[i]]; j >= 0; j--) {
24             for (int k = max(0, j - s); k <= min(sz[e[i]], j); k++) {
25                 f[j] = max(f[j], f[j - k] + k * (s - (j - k)) + (sz[e[i]] - k) * (j - k));
26             }
27         }
28         s += sz[e[i]];
29     }
30     return ret + *max_element(f, f + sz[u]);
31 }
32 
33 int main() {
34     int n;
35     scanf("%d", &n);
36     memset(head, -1, sizeof(head));
37     for (int i = 2; i <= n; i++) {
38         int x;
39         scanf("%d", &x);
40         add(x, i);
41     }
42     printf("%d", dfs(1));
43     
44     return 0;
45 }

  当最近公共祖先固定后,看状态转移的代码:

1 for (int i = head[u], s = 0; i != -1; i = ne[i]) {
2     for (int j = s + sz[e[i]]; j >= 0; j--) {
3         for (int k = max(0, j - s); k <= min(sz[e[i]], j); k++) {
4             f[j] = max(f[j], f[j - k] + k * (s - (j - k)) + (sz[e[i]] - k) * (j - k));
5         }
6     }
7     s += sz[e[i]];
8 }

  可以知道计算量大约为$$m \cdot S_m + s_2 \cdot S_1 + s_3 \cdot S_2 + \ldots + s_m \cdot S_{m - 1}$$

  其中$m \cdot S_m$表示总循环次数。$s_2 \cdot S_1 + s_3 \cdot S_2 + \ldots + s_m \cdot S_{m - 1}$表示最里面那层循环的代码的总计算量。考虑每一个节点都作为最近公共祖先的情况,那么整一个dp的计算量大概就是$$\begin{align*} & \ \ \ \ \sum\limits_{x=1}^{n}{\left(m_x \cdot S_{m_x} + s_{x,2} \cdot S_{x,1} + s_{x,3} \cdot S_{x,2} + \ldots + s_{x,m} \cdot S_{x,m-1} \right)} \\ &\leq n^2 + \sum\limits_{x=1}^{n}{\left(s_{x,2} \cdot S_{x,1} + s_{x,3} \cdot S_{x,2} + \ldots + s_{x,m} \cdot S_{x,m-1} \right)} \\ &\leq n^2 + \frac{n \cdot (n - 1)}{2} \end{align*}$$

  这里简单证明一下$\sum\limits_{x=1}^{n}{\left(s_{x,2} \cdot S_{x,1} + s_{x,3} \cdot S_{x,2} + \ldots + s_{x,m} \cdot S_{x,m-1} \right)} \leq \frac{n \cdot (n - 1)}{2}$。通过几何意义进行解释,现在有一个由$n$个节点,没有任何边的无向图。可以把$s_{x,j} \cdot S_{x,j-1}$理解成在以$x$构成的子树中,其中以第$j$个儿子为根的子树中的每一个点与前$j-1$个儿子为根的每一个子树中的所有节点连一条边,这样就会有$s_{x,j} \cdot S_{x,j-1}$条边。每一条边只会出现一次(因为每次都在子树内部连边),而一个由$n$个节点构成的无向图最多有$C_{n}^{2} = \frac{n \cdot (n - 1)}{2}$条边,因此上界就是$\frac{n \cdot (n - 1)}{2}$。

  因此时间复杂度为$O(n^2)$。

 

参考资料

  Codeforces Round #890 (Div. 2) Editorial:https://codeforces.com/blog/entry/119058

标签:limits,cdot,PermuTree,节点,leq,int,version,E1,ldots
From: https://www.cnblogs.com/onlyblues/p/17611803.html

相关文章

  • Codeforces Round 890 (Div. 2) supported by Constructor Institute A-E1
    An=50非常小所以直接暴力枚举枚举每次把某个数以下的全部减完然后看一下是否上升就行 https://codeforces.com/contest/1856/submission/217275334  B题直接贪心前面优先放最小的最后一个放最大的 然后如果重复了就到前面去看能不能调整一下 https://codeforces.......
  • IE浏览器如何设置默认内核版本,IE11怎么设置默认以IE8的方式解析
    今天修复项目兼容性BUG,用IE11兼容模式调试IE8上的问题,发现每次关闭再打开F12都会以IE11的模式加载,网上搜了一下也没找到怎么设置,不过自己找了找,发现在仿真里可以保存当前设置,凑合可以用吧。但是关闭F12工具后,默认会切换回F11模式,可以通过保留仿真设置里防止其自动切回11。......
  • node14 升级 node16 后 vue2 项目中 sass 报错问题
    起因不知道因为个什么手贱把之前的node14版本卸载了去官网重新下载安装了一下node,最近版本升级到了node16,以为应该不会有什么问题吧,结果把项目一跑,我勒个去,一堆飘红的,看控制台提示主要是这个node-sass报的错。  #卸载npmuninstallnode-sasssass-loader#重新安......
  • /lib64/libstdc++.so.6: version `GLIBCXX_3.4.26' not found
    原因使用的gcc没有找到对应的glib库。每个版本的glib都会有改变,所以使用的时候必须匹配。大部分是因为自己编译升级了gcc,再用新的gcc编译程序时没有找到当时匹配的类库。查找原因报错提示很明确了,/lib64/libstdc++.so.6中没有找到GLIBCXX_3.4.26版本内容。正常情况/lib64/lib......
  • Codeforces Round 890 (Div. 2) A-E1
    A.TalesofaSort题意:给出一个长为n的数组a,每次操作可以使得所有的数-1,最小不会小于0,问至少需要多少次操作才能使得a变得有序。Solution把数组a排序,从大到小遍历,如果当前的\(a[i]\)不是原来的话,那么要想让它有序,必须进行当前的\(a[i]\)次操作,这样才能使得它有序voidsolve()......
  • CodeForces 1856E1 PermuTree (easy version)
    洛谷传送门CF传送门考虑局部贪心,假设我们现在在\(u\),我们希望\(u\)不同子树中的\((v,w),a_v<a_u<a_w\)的对数尽量多。我们实际上只关心子树内\(a_u\)的相对大小关系,不关心它们具体是什么。如果\(u\)只有两个儿子\(v,w\),我们可以让\(v\)子树内的\(a\)全部......
  • CodeForces 1856E2 PermuTree (hard version)
    洛谷传送门CF传送门考虑局部贪心,假设我们现在在\(u\),我们希望\(u\)不同子树中的\((v,w),a_v<a_u<a_w\)的对数尽量多。我们实际上只关心子树内\(a_u\)的相对大小关系,不关心它们具体是什么。如果\(u\)只有两个儿子\(v,w\),我们可以让\(v\)子树内的\(a\)全部......
  • 【刷题笔记】6. ZigZag Conversion
    题目Thestring "PAYPALISHIRING" iswritteninazigzagpatternonagivennumberofrowslikethis:(youmaywanttodisplaythispatterninafixedfontforbetterlegibility)PAHNAPLSIIGYIRAndthenreadlinebyline: &q......
  • 顶配涨至近2万 该买还是买!iPhone15正面曝光 与历代苹果手机对比边框爆窄
    从曝光的iPhone15正面渲染图来看,其颜值确实要比上代又提高不少。外媒放出了一组iPhone15Pro的正面渲染图照,从图片看边框非常的窄,与历代iPhone边框对比,这个特点更是被放大。其实之前就有消息称,苹果在新iPhone上使用一种称为LIPO的技术来实现极窄边框,该技术曾在AppleWatch上......
  • k8s部署DataEase1.16.0cluster模式
    1.下载官方helm  chart包下载地址:https://github.com/mfanoffice/dataease-helm/releases,当前最新为1.16.0#下载并解压helmchart包wgethttps://github.com/mfanoffice/dataease-helm/releases/download/1.16.0/dataease-1.16.0.tgztarxfdataease-1.16.0.tgzcddataease......