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春季顶级见!
标签:strength,PAT,朋友,题解,最小,2021,节点,朋友圈 来源: https://www.cnblogs.com/rhmemory/p/15256720.html