2021年秋季 PAT 顶级 题解

2021年秋季 PAT 顶级 题解

第一题

题意:

给你一个堆+搜索树的新定义,然后要你求这颗树的层序遍历

它的定义是这样的:

对于一个节点有两个值 分别记作key 和 priority

其中只看Key仅仅是作为搜索树

其中只看priority仅仅是作为最小堆(也可以是最大堆,但是题目中要求的只是最小堆

分析:
对于第二位priority要是最小堆,那么毫无疑问根节点一定是最小的,那么就已经确定了一个节点

如果我们也按照树的递归生成来确定之后节点的位置,可以确定的是一定是按照priority递增顺序添加节点的,这样就能保证是一个最小堆(但不保证是完全二叉树

因此,我们先将整个节点按照第二维从小到大排序,然后依次按照第一维(二叉搜索树)插入当前树中即可

第二题

题意:

一共n个人,给你m对好朋友,其中定义strength > 0代表是好朋友, < 0不是好朋友,这样要使得他们是好朋友需要付出的代价是abs(strength)

第一个要求的是   给定的好朋友集合中的朋友圈信息,按照一定的排序规则进行排序

第二个要求的是   在给定好朋友几集合中的信息,如果要让他们都是好朋友所需要的最小代价

如果不存在strength的,甚至连 < 0的strength都没有的话,使他们成为好朋友需要花费1e4个代价

PS:朋友间具有传递性

分析:

...一看传递性,秒上并查集!

先对给的朋友信息按照从大到小排序

那么就是并查集统计一下给定 > 0 strength的朋友圈内的信息然后进行输出

为了之后统计方便,每次合并两个人都需要

1、树根都是编号最小的

2、统计朋友圈总人数...(也就是这棵树中有多少个节点

3、统计朋友圈内最小的strength(也就是题目所说的unite strength

然后按照一定的顺序输出即可

...

求最小的花费

由于数组之前按照strength从大到小排序

那么顺着之前 < 0的strength开始,看看这个strength能不能合并这两个集合 ,如果合并了,那么花费加上abs(strength)

之后遍历完题目给的关系后,如果还有没合并的集合,那么就是需要花费1e4去合并了,这时候的花费 = (当前朋友圈个数 - 1)*1e4

为啥贪心先取给定的朋友关系呢,因为abs(strength) <= 1e3

那么这道题就做完了

第三题

题意:

两个人堆摩天大楼

给定一串长度为n的序列,序列的值ai ∈ [1,3]

第i此可以由A拿走ai的值,但是这时候必须保证Ai拿走ai的值之后加上之前拿走值的总和要大于B拿走的值

当然也可以由B拿走,拿走后所取的总值也需要大于A才行,不然这个决策就错了

(这里A,B代表的是两个人

求方案数 n <= 1e5

分析:

按照以往PAT第三题的niao性,第三题都是DP,这道题也是没毛病吧

定义状态:

我们很容易就会发现每次拿完数之后,A,B无非他俩的差是 1 ,2 ,3,和 > 3

那么状态定义为当为第i个数时,A - B的差值 = K的方案数为dp[i][k]

其中k ∈ {< -3 、-3、-2、-1、0、1、2、3、> 3}

那么转移方程!!!

请看我的代码。。。

PS:由于这题是赛后补的,现在暂时还不知道是否对的,但是能给的样例基本上都对了...

点击查看代码
#include <iostream>
using namespace std;
const int MAXN = 1e5 + 7;
const int MOD = 1e9 + 7;
typedef long long ll;
ll dp[MAXN][10];
/*
a[i]   =   1             2             3 
0-> -4   -3/-4       -3/-2/-4     -1/-2/-3/-4
1-> -3    -2             -1            0
2-> -2    -1             0             1
3-> -1    0              1             2
4-> 0    -1/1          -2/2          -3/3
5-> 1     0             -1            -2
6-> 2     1             0             -1
7-> 3     2             1              0
8-> 4     3/4         2/3/4         1/2/3/4
*/
int a[MAXN];
/*
3
1 3 3
*/
void solve()
{
	int n;
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)	scanf("%d",&a[i]);
	ll ans = 0;
	dp[0][4] = 1;
	for(int i = 1;i <= n;++i)
	{
		if(a[i] == 1)
		{
			dp[i][0] = dp[i - 1][0] + dp[i - 1][1];
			dp[i][1] = dp[i - 1][2];
			dp[i][2] = dp[i - 1][3];
			dp[i][3] = dp[i - 1][4];
			dp[i][4] = dp[i - 1][3] + dp[i - 1][5];
			dp[i][5] = dp[i - 1][4];
			dp[i][6] = dp[i - 1][5];
			dp[i][7] = dp[i - 1][6];
			dp[i][8] = dp[i - 1][7] + dp[i - 1][8];
		}
		else if(a[i] == 2)
		{
			dp[i][0] = dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2];
			dp[i][1] = dp[i - 1][3];
			dp[i][2] = dp[i - 1][4];
			dp[i][3] = dp[i - 1][5];
			dp[i][4] = dp[i - 1][2] + dp[i - 1][6];
			dp[i][5] = dp[i - 1][3];
			dp[i][6] = dp[i - 1][4];
			dp[i][7] = dp[i - 1][5];
			dp[i][8] = dp[i - 1][6] + dp[i - 1][7] + dp[i - 1][8];
		}
		else
		{
			dp[i][0] = dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][3];
			dp[i][1] = dp[i - 1][4];
			dp[i][2] = dp[i - 1][5];
			dp[i][3] = dp[i - 1][6];
			dp[i][4] = dp[i - 1][1] + dp[i - 1][7];
			dp[i][5] = dp[i - 1][2];
			dp[i][6] = dp[i - 1][3];
			dp[i][7] = dp[i - 1][4];
			dp[i][8] = dp[i - 1][5] + dp[i - 1][6] + dp[i - 1][7] + dp[i - 1][8];
		}
		for(int j = 0;j < 9;++j)	dp[i][j] %= MOD;
	}
	for(int i = 0;i < 9;++i)
	ans = (ans + dp[n][i]) % MOD;
	printf("%lld\n",ans);
}
int main()
{
//	freopen("input.txt","r",stdin);
//	freopen("ress.out","w",stdout);
	int t = 1;
//	scanf("%d",&t);
	while(t--)
	solve();
	return 0;
}

PS:最后记录一下自己PAT顶级的经历

还是不够自信,第三题状态没想错,就是为0的时候只考虑了一个人多的情况

应该考虑A多a[]i和B多a[i]两种情况才是正确的!如果当时将样例

2

1 1

再多debug一下就A了(也许!,PAT春季顶级见!

最后:
今天教育超市有比赛的题了

用上面的代码交了第三题,过了

总结:

沉住气,有耐心,多自信。

posted @ 2021-09-11 20:42  K0njac  阅读(347)  评论(0编辑  收藏  举报