2018 NOIP 普及组

T1 标题统计

题目点击→计蒜客 [NOIP2018] 标题统计

题目描述
凯凯刚写了一篇美妙的作文,请问这篇作文的标题中有多少个字符?

注意:标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字符数时,空格和换行符不计算在内。

输入格式

输入文件只有一行,一个字符串 s s s

输出格式

输出文件只有一行,包含一个整数,即作文标题的字符数(不含空格和换行符)。

数据范围

规定 ∣ s ∣ |s| s 表示字符串 s s s 的长度(即字符串中的字符和空格数)。

对于 40 % 40\% 40% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 \le |s| \le 5 1s5,保证输入为数字字符及行末换行符。

对于 80 % 80\% 80% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 \le |s| \le 5 1s5,输入只可能包含大、小写英文字母、数字字符及行末换行符。

对于 100 % 100\% 100% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 \le |s| \le 5 1s5,输入可能包含大、小写英文字母、数字字符、空格和行末换行符。

样例说明

样例1:

标题中共有 3 3 3 个字符,这 3 3 3 个字符都是数字字符。

样例2:

标题中共有 5 5 5 个字符,包括 1 1 1 个大写英文字母, 1 1 1 个小写英文字母和 2 2 2 个数字字符,还有 1 1 1 个空格。由于空格不计入结果中,故标题的有效字符数为 4 4 4 个。

T1分析

送分题…

#include <iostream>

using namespace std;

int main()
{
    string s;
    int ans=0;
    while (cin >> s) 
        ans+=s.length();
    cout << ans << endl;
    return 0;
}

T2 龙虎斗

题目点击→计蒜客 [NOIP2018] 龙虎斗

题目描述
轩轩和凯凯正在玩一款叫《龙虎斗》的游戏,游戏的棋盘是一条线段,线段上有 n n n 个兵营(自左至右编号 1 1 1 ~ n n n),相邻编号的兵营之间相隔 1 1 1 厘米,即棋盘为长度为 n − 1 n - 1 n1 厘米的线段。 i i i 号兵营里有 c i c_i ci 位工兵。

下面图 1 1 1 n = 6 n = 6 n=6 的示例:

1 1 1. n = 6 n = 6 n=6 的示例

轩轩在左侧,代表 “龙”;凯凯在右侧,代表 “虎”。他们以 m m m 号兵营作为分界,靠左的工兵属于龙势力,靠右的工兵属于虎势力,而 m m m 号兵营中的工兵很纠结,他们不属于任何一方

一个兵营的气势为:该兵营中的工兵数 × \times × 该兵营到 m m m 号兵营的距离;参与游戏一方的势力定义为:属于这一方所有兵营的气势之和。

下面图 2 2 2 n = 6 , m = 4 n = 6, m = 4 n=6,m=4 的示例,其中红色为龙方,黄色为虎方:

2 2 2. n = 6 , m = 4 n = 6, m = 4 n=6,m=4 的示例

游戏过程中,某一刻天降神兵,共有 s 1 s_1 s1 位工兵突然出现在了 p 1 p_1 p1 号兵营。作为轩轩和凯凯的朋友,你知道如果龙虎双方气势差距太悬殊,轩轩和凯凯就不愿意继续玩下去了。为了让游戏继续,你需要选择一个兵营 p 2 p_2 p2,并将你手里的 s 2 s_2 s2 位工兵 全部 派往兵营 p 2 p_2 p2,使得双方气势差距尽可能小。

注意:你手中的工兵落在哪个兵营,就和该兵营中其他工兵有相同的势力归属(如果落在 m m m 号兵营,则不属于任何势力)。

输入格式

输入文件的第一行包含一个正整数 n n n,代表兵营的数量。

接下来的一行包含 n n n 个正整数,相邻两数之间以一个空格分隔,第 i i i 个正整数代表编号为 i i i 的兵营中起始时的工兵数量 c i c_i ci

接下来的一行包含四个正整数,相邻两数间以一个空格分隔,分别代表 m , p 1 , s 1 , s 2 m,p_1,s_1,s_2 m,p1,s1,s2

输出格式

输出文件有一行,包含一个正整数,即 p 2 p_2 p2,表示你选择的兵营编号。

如果存在多个编号同时满足最优,取最小的编号。

数据范围

1 < m < n , 1 ≤ p 1 ≤ n 1 < m < n, 1 \le p_1 \le n 1<m<n,1p1n

对于 20 % 20\% 20% 的数据, n = 3 , m = 2 , c i = 1 , s 1 , s 2 ≤ 100 n = 3, m = 2, c_i = 1, s_1, s_2 \le 100 n=3,m=2,ci=1,s1,s2100

另有 20 % 20\% 20% 的数据, n ≤ 10 , p 1 = m , c i = 1 , s 1 , s 2 ≤ 100 n \le 10, p_1 = m, c_i = 1, s_1, s_2 \le 100 n10,p1=m,ci=1,s1,s2100

对于 60 % 60\% 60% 的数据, n ≤ 100 , c i = 1 , s 1 , s 2 ≤ 100 n \le 100, c_i = 1, s_1, s_2 \le 100 n100,ci=1,s1,s2100

对于 80 % 80\% 80% 的数据, n ≤ 100 , c i , s 1 , s 2 ≤ 100 n \le 100, c_i,s_1,s_2 \le 100 n100,ci,s1,s2100

对于 100 % 100\% 100% 的数据, n ≤ 1 0 5 , c i , s 1 , s 2 ≤ 1 0 9 n \le 10^5, c_i, s_1, s_2 \le 10^9 n105,ci,s1,s2109

样例说明

样例 1

双方以 m = 4 m=4 m=4 号兵营分界,有 s 1 = 5 s_1 =5 s1=5 位工兵突然出现在 p 1 = 6 p_1 =6 p1=6 号兵营。

龙方的气势为: 2 × ( 4 − 1 ) + 3 × ( 4 − 2 ) + 2 × ( 4 − 3 ) = 14 \displaystyle 2 \times (4 - 1) + 3 \times (4 - 2) + 2 \times (4 - 3) = 14 2×(41)+3×(42)+2×(43)=14

虎方的气势为: 2 × ( 5 − 4 ) + ( 3 + 5 ) × ( 6 − 4 ) = 18 \displaystyle 2 \times (5 - 4) + (3 + 5) \times (6 - 4) = 18 2×(54)+(3+5)×(64)=18

当你将手中的 s 2 = 2 s_2 = 2 s2=2 位工兵派往 p 2 = 2 p_2 = 2 p2=2 号兵营时,龙方的气势变为:

14 + 2 × ( 4 − 2 ) = 18 \displaystyle 14 + 2 \times (4 - 2) = 18 14+2×(42)=18

此时双方气势相等。

样例 2

双方以 m = 5 m = 5 m=5 号兵营分界,有 s 1 = 1 s_1 =1 s1=1 位工兵突然出现在 p 1 = 4 p_1 =4 p1=4 号兵营。

龙方的气势为: 1 × ( 5 − 1 ) + 1 × ( 5 − 2 ) + 1 × ( 5 − 3 ) + ( 1 + 1 ) × ( 5 − 4 ) = 11 \displaystyle 1 \times (5 - 1) + 1 \times (5 - 2) + 1 \times (5 - 3) + (1 + 1) \times (5 - 4) = 11 1×(51)+1×(52)+1×(53)+(1+1)×(54)=11虎方的气势为: 16 × ( 6 − 5 ) = 16 \displaystyle 16 \times (6 - 5) = 16 16×(65)=16当你将手中的 s 2 = 1 s_2 = 1 s2=1 位工兵派往 p 2 = 1 p_2 = 1 p2=1 号兵营时,龙方的气势变为: 11 + 1 × ( 5 − 1 ) = 15 \displaystyle 11 + 1 \times (5 - 1) = 15 11+1×(51)=15此时可以使双方气势的差距最小。

样例 3

网盘链接:https://pan.baidu.com/s/1kzJKaoFSBoUggGm6-_GAJA 密码:md6k

T2分析

先算出左边和右边的和,然后暴力模拟当前 s 2 s_2 s2 放在 [ 1 , n ] [1,n] [1,n] 中任意一个位置的情况,求出一个最小差值 a b s ( l e f t − r i g h t ) abs(left-right) abs(leftright)即可
注意细节, n ≤ 1 0 5 n≤10^5 n105, c i , s 1 , s 2 ≤ 1 0 9 c_i,s_1,s_2≤10^9 ci,s1,s2109,求和的结果会达到 1 0 14 10^{14} 1014,所以要long long,以及 p 1 p_1 p1可能在左边也可能在右边,也可能在 m m m 上,还有就是手里这 s 2 s_2 s2 个人同样是可以放在 m m m 中的

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <vector> 
using namespace std;

long long a[100100];

int main()
{
	int n;scanf("%d",&n);
	for (int i = 1 ; i <= n ; ++i)
		scanf("%lld",&a[i]);
	long long m,p1,s1,s2;
	scanf("%lld%lld%lld%lld",&m,&p1,&s1,&s2);
	long long left = 0,right = 0;
	for (int i = 1 ; i < m  ; ++i){
		left += a[i] * (m - i);
	}
	for (int i = m + 1 ; i <= n ; ++i){
		right += a[i] * (i - m);
	}
	if (p1 < m) left += (m - p1) * s1;
	if (p1 > m) right += (p1 - m) * s1;
	long long sum = abs(right - left),ans = m;
	for (int i = 1 ; i <= n ; ++i){
		long long vl = left;
		long long vr = right;
		if (i < m) vl += (m - i) * s2;
		if (i > m) vr += (i - m) * s2;
		long long vsum = abs(vl - vr);
		if (vsum < sum){
			ans = i;
			sum = vsum;
		}
	}
	printf("%lld\n",ans);
	return 0;
} 

T3 摆渡车

题目点击→ 计蒜客 [NOIP2018] 摆渡车

题目描述
n n n 名同学要乘坐摆渡车从人大附中前往人民大学,第 i i i 位同学在第 t i t_i ti 分钟去等车。只有一辆摆渡车在工作,但摆渡车容量可以视为无限大。摆渡车从人大附中出发、把车上的同学送到人民大学、再回到人大附中(去接其他同学),这样往返一趟总共花费 m m m 分钟(同学上下车时间忽略不计)。摆渡车要将所有同学都送到人民大学。

凯凯很好奇,如果他能任意安排摆渡车出发的时间,那么这些同学的等车时间之和最小为多少呢?

注意:摆渡车回到人大附中后可以即刻出发。

输入格式

第一行包含两个正整数 n , m n,m n,m,以一个空格分开,分别代表等车人数和摆渡车往返一趟的时间。

第二行包含 n n n 个正整数,相邻两数之间以一个空格分隔,第 i i i 个非负整数 t i t_i ti 代表第 i i i 个同学到达车站的时刻。

输出格式

输出一行,一个整数,表示所有同学等车时间之和的最小值(单位:分钟)。

数据范围

对于 10 % 10\% 10% 的数据, n ≤ 10 , m = 1 , 0 ≤ t i ≤ 100 n \le 10, m=1, 0\le t_i \le 100 n10,m=1,0ti100

对于 30 % 30\% 30% 的数据, n ≤ 20 , m ≤ 2 , 0 ≤ t i ≤ 100 n \le 20, m \le 2, 0 \le t_i \le 100 n20,m2,0ti100

对于 50 % 50\% 50% 的数据, n ≤ 500 , m ≤ 100 , 0 ≤ t i ≤ 1 0 4 n \le 500, m \le 100, 0 \le t_i \le 10^4 n500,m100,0ti104

另有 20 % 20\% 20% 的数据, n ≤ 500 , m ≤ 10 , 0 ≤ t i ≤ 4 × 1 0 6 n \le 500, m \le 10, 0 \le t_i \le 4 \times 10^6 n500,m10,0ti4×106

对于 100 % 100\% 100% 的数据, n ≤ 500 , m ≤ 100 , 0 ≤ t i ≤ 4 × 1 0 6 n \le 500, m \le 100, 0 \le t_i \le 4 \times 10^6 n500,m100,0ti4×106

样例说明

样例 1

同学 1 1 1 和同学 4 4 4 在第 3 3 3 分钟开始等车,等待 0 0 0 分钟,在第 3 3 3 分钟乘坐摆渡车 出发。摆渡车在第 4 4 4 分钟回到人大附中。

同学 2 2 2 和同学 3 3 3 在第 4 4 4 分钟开始等车,等待 0 0 0 分钟,在第 4 4 4 分钟乘坐摆渡车 出发。摆渡车在第 5 5 5 分钟回到人大附中。

同学 5 5 5 在第 5 5 5 分钟开始等车,等待 0 0 0 分钟,在第 5 5 5 分钟乘坐摆渡车出发。自此所有同学都被送到人民大学。总等待时间为 0 0 0

样例 2

同学 3 3 3 在第 1 1 1 分钟开始等车,等待 0 0 0 分钟,在第 1 1 1 分钟乘坐摆渡车出发。摆渡车在第 6 分钟回到人大附中。

同学 4 4 4 和同学 5 5 5 在第 5 5 5 分钟开始等车,等待 1 1 1 分钟,在第 6 6 6 分钟乘坐摆渡车出发。摆渡车在第 11 11 11 分钟回到人大附中。

同学 1 1 1 在第 11 11 11 分钟开始等车,等待 2 2 2 分钟;同学 2 2 2 在第 13 13 13 分钟开始等车,等待 0 0 0 分钟。他/她们在第 13 13 13 分钟乘坐摆渡车出发。自此所有同学都被送到人民大学。总等待时间为 4 4 4。可以证明,没有总等待时间小于 4 4 4 的方案。

T3分析

dp或者记忆化搜索。
相对来说dp对算法要求高一些,需要考虑状态转移的优化或者剪枝

解法 I

记忆化搜索相对来说简单一些,比赛的时候,既然可以想的到记忆化搜索,何必再去推个dp公式呢…当然10分钟解决dp所有问题的dalao就不用考虑这种东西了…
首先考虑一下这个问题中存在的状态,显然是 [ 人 ] [ 时 间 ] [人][时间] [][]两者的结合,那么考虑 f [ i ] [ j ] f[i][j] f[i][j],第 i i i 个人,考虑时间 j j j ,能达到的最佳方案,但是显然 j j j 会达到 4 × 1 0 6 4 \times 10^6 4×106,但是这里我们可以发现一件事,一个人是不可能等待超过 m m m 分钟,所以其实状态可以表示成
f [ i ] [ j ] 表 示 到 第 i 个 人 , 他 的 等 待 时 间 是 j 的 时 候 能 达 到 的 最 佳 方 案 f[i][j]表示到第 i 个人,他的等待时间是 j 的时候能达到的最佳方案 f[i][j]ij
那么思考一下状态转移…显然最容易想到的状态就是对当前状态 f [ i ] [ j ] f[i][j] f[i][j] 考虑这辆车直接发车,或者等第 i + 1 i + 1 i+1个同学来,或者继续等到 i + 2 i + 2 i+2 个同学来。
然后考虑一下复杂度,显然 O ( n 2 ∗ m ) O(n^2*m) O(n2m)足矣…那就,做完了呀

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector> 
using namespace std;
int n,m;
int a[10000];
int f[550][550]; //第i个人等待时间为j的最佳结果 
int solve(int now,int Time){
	//n个人都结束了则返回0 
	if (now >= n ) return 0;
	//若当前时间<当前同学的来的时间,则将时间拉到当前同学来的时间 
	if (a[now] > Time) return solve(now,a[now]);
	//当前状态出现过 
	if (f[now][Time - a[now]]) return f[now][Time - a[now]];
	int sum = 0,ans = 0;
	int i = now;
	for (; i < n ;++i){
		if (a[i] > Time) break;
		sum += a[i];
		ans += Time - a[i];
	}
	ans += solve(i , Time + m);
	for (; i < n ; ++i){
		sum += a[i];
		ans = min(ans, solve(i + 1,a[i] + m) + a[i] * (i - now + 1) - sum);
	}
	return f[now][Time - a[now]] = ans; 
}


int main(){
	scanf("%d%d",&n,&m);
	for (int i = 0 ; i < n ; ++i) scanf("%d",&a[i]);
	sort(a,a+n);
	printf("%d\n",solve(0,0));
	return 0;
} 

解法 II

引理:对于每个乘客,如果他开始等待的时刻为 t t t,那么搭载他的车的发车时间 t 0 ∈ [ t , t + m ) t_0 \in [t, t + m) t0[t,t+m)

证明:如果存在一种发车时间 ≥ t + m \ge t + m t+m,那么发车时间一定可以提早若干个 m m m 使得 t 0 t_0 t0 到达 [ t , t + m ) [t, t + m) [t,t+m)。这样不会影响其他 ≥ t + m \ge t + m t+m 的发车时间,不会干扰后面的人等车。

我们考虑 DP 状态涉及: f [ i , j ] f[i, j] f[i,j] 表示搭载了前 i i i 个人,搭载第 i i i 个人的摆渡车的发车时间为 t i + j t_i + j ti+j 的最小等候时间总和。朴素的转移方程为:

f [ i , j ] = min ⁡ 0 ≤ k < i , 0 ≤ p < m { f [ k , p ] + c o s t ( k + 1 , i , t i + j ) } \displaystyle f[i,j] = \min_{0 \le k < i, 0 \le p < m}\{f[k, p] + cost(k + 1, i, t_i + j)\} f[i,j]=0k<i,0p<mmin{ f[k,p]+cost(k+1,i,ti+j)}

其中 c o s t ( i , j , k ) cost(i, j, k) cost(i,j,k) 表示第 i i i ~ j j j 个人在 k k k 时间乘车的等候时间总和。注意转移过程中有 t i + j ≥ t k + p + m t_i + j \ge t_k + p + m ti+jtk+p+m(当前这趟车比上一趟车至少晚 m m m)的限制!

这个式子直接计算是 O ( n 3 m 2 ) \mathcal{O}(n^3m^2) O(n3m2) 的,接下来考虑转移如何优化。上述式子中,我们通过对 t i t_i ti 做前缀和可以 O ( 1 ) \mathcal{O}(1) O(1) 计算出 c o s t cost cost 的值。我们再记 g [ i , j ] = min ⁡ 0 ≤ j < m f [ i , j ] g[i, j] = \min_{0 \le j < m}f[i, j] g[i,j]=min0j<mf[i,j](这个前缀 min ⁡ \min min 可以在转移过程中维护),转移方程化为 f [ i , j ] = min ⁡ 0 ≤ k < i { g [ k , x ] + c o s t } f[i, j] = \min_{0 \le k < i}\{g[k, x] + cost\} f[i,j]=min0k<i{ g[k,x]+cost},其中 x = min ⁡ ( m − 1 , t i + j − t k − m ) x = \min(m - 1, t_i + j - t_k - m) x=min(m1,ti+jtkm) x ≥ 0 x \ge 0 x0,时间复杂度优化为 O ( n 2 m ) \mathcal{O}(n^2m) O(n2m)

#include <cstdio>
#include <algorithm>
int t[505], p[1005 * 105];
long long f[1005 * 105], g[505][105];
int main() {
    
    
    int n, m, P = 0; scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) {
    
    
        scanf("%d", t + i);
        for(int k = 0; k <= m; ++k) p[++P] = t[i] + k;
    }
    std::sort(t + 1, t + n + 1);
    std::sort(p + 1, p + P + 1); P = std::unique(p + 1, p + P + 1) - p - 1;
    t[0] = -4e6;
    int ans = 2017011328;
    for(int i = 1, k = 0, pi; i <= P; ++i) {
    
    
        f[i] = ans; pi = p[i];
        while(k < n && t[k + 1] <= pi) {
    
    
            ++k;
            for(int i = 0; i <= m; ++i) g[k][i] = 2017011328;
        }
        for(int j = k, c = 0; j >= 1; --j) {
    
    
            c += pi - t[j];
            if(t[j - 1] != t[j] && pi - t[j - 1] >= m) f[i] = std::min(f[i], c + g[j - 1][std::min(m, pi - m - t[j - 1])]);
        }
        if(g[k][std::min(m, pi - t[k])] > f[i]) g[k][std::min(m, pi - t[k])] = f[i];
        for(int j = 1; j <= m; ++j) g[k][j] = std::min(g[k][j], g[k][j - 1]);
    }
    printf("%lld\n", g[n][m]);
}

T4 对称二叉树

点击查看→ 计蒜客 [NOIP2018] 对称二叉树

题目描述
一棵有点权的有根树如果满足以下条件,则被轩轩称为 对称二叉树

    1. 二叉树;
    1. 将这棵树 所有 节点的左右子树交换,新树和原树对应位置的结构相同且点权相等。

下图中节点内的数字为权值,节点外的 i d id id 表示节点编号。

现在给出一棵二叉树,希望你找出它的一棵子树,该子树为对称二叉树,且节点数最多。请输出这棵子树的节点数。

注意:只有树根的树也是对称二叉树。本题中约定,以节点 T T T 为子树根的一棵 “子树” 指的是:节点 T T T 和它的 全部 后代节点构成的二叉树。

输入格式

第一行一个正整数 n n n,表示给定的树的节点的数目,规定节点编号 1 1 1~ n n n,其中节点 1 1 1 是树根。

第二行 n n n 个正整数,用一个空格分隔,第 i i i 个正整数 v i v_i vi 代表节点 i i i 的权值。

接下来 n n n 行,每行两个正整数 l i , r i l_i, r_i li,ri,分别表示节点 i i i 的左右孩子的编号。如果不存在左 / 右孩子,则以 − 1 -1 1 表示。两个数之间用一个空格隔开。

输出格式

输出文件共一行,包含一个整数,表示给定的树的最大对称二叉子树的节点数。

数据范围

25 25 25 个测试点。

v i ≤ 1000 v_i \le 1000 vi1000

测试点 1 1 1 ~ 3 3 3 n ≤ 10 n \le 10 n10,保证根结点的左子树的所有节点都没有右孩子,根结点的右子树的所有节点都没有左孩子。

测试点 4 4 4 ~ 8 8 8 n ≤ 10 n \le 10 n10

测试点 9 9 9 ~ 12 12 12 n ≤ 1 0 5 n \le 10^5 n105,保证输入是一棵 “满二叉树”。

测试点 13 13 13 ~ 16 16 16 n ≤ 1 0 5 n \le 10^5 n105,保证输入是一棵 “完全二叉树”。

测试点 17 17 17 ~ 20 20 20 n ≤ 1 0 5 n \le 10^5 n105,保证输入的树的点权均为 1 1 1

测试点 21 21 21 ~ 25 25 25 n ≤ 1 0 6 n \le 10^6 n106

本题约定:

层次:节点的层次从根开始定义起,根为第一层,根的孩子为第二层。树中任一节点的层次等于其父亲节点的层次加 1 1 1

树的深度:树中节点的最大层次称为树的深度。

满二叉树:设二叉树的深度为 h h h,且二叉树有 2 h − 1 2^h - 1 2h1 个节点,这就是满二叉树。

完全二叉树:设二叉树的深度为 h h h,除第 h h h 层外,其它各层的结点数都达到最大个数,第 h h h 层所有的结点都连续集中在最左边,这就是完全二叉树。

样例说明

样例 1

最大的对称二叉子树为以节点 2 2 2 为树根的子树,节点数为 1 1 1

样例 2

最大的对称二叉子树为以节点 7 7 7 为树根的子树,节点数为 3 3 3

T4分析

第三题做太久了就没想到吧这第四题跟第三题比起来跟送的一样…
没啥东西…顶多也就是个PAT难度的题目…
首先考虑一点,直接check的复杂度是多少,乍一看以为是 O ( n 2 ) O(n^2) O(n2) 的就基本上崩了。。
实际上考虑最慢的情况就是一颗完全对称的树,那么遍历一次的复杂度是多少呢? O ( n ) O(n) O(n)因为每个点都要被访问到,然而并不是这样…显然每次左右分别往下遍历的话,遍历一次的复杂度也就只有 O ( l o g n ) O(logn) O(logn)罢了…所以…就做完了呀… O ( n l o g n ) O(nlogn) O(nlogn)就过了…甚至还可以做一下优化,比如先预处理出当前节点下子树的大小,那么每次在check之前可以判断…加个最优化剪枝虽然应该没什么大用

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector> 
using namespace std;
int n;
int a[1001000],lson[1001000],rson[1001000];

int check(int l,int r){
	if (l == -1 && r == -1) return 1;
	if (l == -1 || r == -1) return -1;
	if (a[l] != a[r]) return -1;
	int lval = check(lson[l],rson[r]);
	int rval = check(rson[l],lson[r]);
	if (lval == -1 || rval == -1) return -1;
	return lval + rval + 1;
}

int main() {
	scanf("%d",&n);
	for (int i = 1 ; i <= n ; ++i) scanf("%d",&a[i]);
	for (int i = 1 ; i <= n ; ++i){
		scanf("%d%d",&lson[i],&rson[i]);
	}
	int ans = 1;
	for (int i = 1 ; i <= n ; ++i){
		int temp = check(lson[i],rson[i]);
		if (temp != -1) ans = max(ans,temp);
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jnxxhzz/article/details/86556446