2021年秋季PAT甲级满分题解与分析

第一题

题目描述

Let’s design a data structure A that combines arrays and linked lists as the following:
At the very beginning, an integer array A0 of length L0 is initialized for the user. When the user tries to access the ith element A[i], if 0≤i<L0 , then A[i] is just A 0 [ i ] A_0[i] A0[i]. Now our system is supposed to return h0 +i×sizeof(int) as the accessed address, where h0 is the initial address of A0 , and sizeof(int) is the size of the array element, which is simply int, taking 4 bytes.
In case there is an overflow of the user’s access (that is, i≥L0 ), our system will declare another array A1 of length L1 . Now A[i] corresponds to A1[j] (It’s your job to figure out the relationship between i and j). If 0≤j<L1 , then h1 +j×sizeof(int) is returned as the accessed address, where h1 is the initial address of A1.And if there is yet another overflow of the user’s access to A1[j], our system will declare another array A2 of length L2 , and so on so forth.
Your job is to implement this data structure and to return the address of any access.

输入

Each input file contains one test case. For each case, the first line gives 2 positive integers N ( ≤ 1 0 4 ) (≤10^4) (104) and K ( ≤ 1 0 3 ) (≤10^3) (103) which are the number of arrays that can be used, and the number of user queries, respectively.
Then N lines follow, each gives 2 positive integers, which are the initial address ( ≤ 1 0 7 ) (≤10^7) (107) and the length (≤100) of an array, respectively. The numbers are separated by spaces. It is guaranteed that there is no overlap of the spaces occupied by these arrays.
Finally, K indices of the elements queried by users are given in the last line. Each index is an integer in the range [0,2^20].

输出

For each query, print in a line the accessed address. If the queried index exceeds the range of all the N arrays, output Illegal Access instead, and this query must NOT be processed.
Print in the last line the total number of arrays that have been declared for the whole process.

思路

这里可能光看有点懵,给大家解释一下,就是说现在有一种数据结构,这种结构由多个数组联合而成,然后告诉你每一个数组的起始地址和长度,然后现在给你一些索引,你要输出对应的地址。就比如
A0 起始地址:13 长度 6
A1 起始地址:100 长度8
A2 起始地址:1000 长度20
假如现在声明第一个索引为5,可以发现A0可以满足,所以5对应的地址为 A 0 [ 5 ] A_0[5] A0[5]为13+45=33
假如第二个为9可以发现A0满足不了,说明这个地址在A1或A2,A0占了六个位置,所以 A [ 9 ] = A 1 [ 3 ] A[9]=A_1[3] A[9]=A1[3]为100
3*4=112
以此类推,如果声明索引大于给定的,那么就打出失败。
输出最后还要输出一个数字表示声明过的数据结构,就比如像上面A0和A1被声明过了,那么输出为2.
看了看题发现是不是挺简单的,错错错!这题是本次通过率最低的,结束时看0.04的通过率,题主也是最后10分钟才看过来,问题就出在要输出被声明过的数量!这个很坑,一开始以为是统计那些不超出范围的对应的那个Ai统计这个数量,但后来发现不是,因此假如输入的索引只有一个20,发现落在A2,那应该输出1?实际要输出3。因为你想你声明A2说明前面两个都声明了…我估计大家也是被卡在这里。。。。这里想清楚后就不难了

代码

#include<iostream>
#include<cstdio>
#include<stdlib.h>
using namespace std;
typedef struct node {
    
    
	int first;
	int len;
}My;
My my[1100000];
int ans[1100000] = {
    
     0 };
int pan[11000000] = {
    
     0 };
int main()
{
    
    
	int N, K;
	cin >> N >> K;
	int num = 0;
	for (int i = 0; i < N; i++)
	{
    
    
		cin >> my[i].first >> my[i].len;
		if (i > 0)
			ans[i] = ans[i - 1] + my[i].len;
		else
			ans[i] = my[i].len;
	}
	for (int i = 0; i < K; i++)
	{
    
    
		int temp;
		cin >> temp;
		int j;
		for (j = 0; j < N; j++)
		{
    
    
			if (ans[j] > temp)
			{
    
    
				break;
			}
		}
		int l;
		int cur;
		if (j == 0)
		{
    
    
			l = temp;
			cur = 0;
		}
		else if (j >= N)
		{
    
    
			printf("Illegal Access\n");
			continue;
		}
		else
		{
    
    
			l = temp - ans[j - 1];
			cur = j;
		}
		printf("%d\n", my[cur].first + l * 4);
		if (num < cur)
		{
    
    
			num = cur;
		}
	}
	printf("%d\n", num + 1);
}

第二题

题目描述

PATers believe that wearing hats makes them look handsome, so wherever they go, everyone of them would wear a hat. One day they came to a restaurant, a waiter collected their hats and piled them up. But then when they were ready to leave, they had to face a stack of hats as shown by the above figure. So your job is to help them line up so that everyone can pick up his/her hat one by one in order without any trouble.
It is known that every hat has a unique size, which is related to the weight of its owner – that is, the heavier one wears larger hat.

输入

Each input file contains one test case. For each case, the first line contains a positive number N ( ≤ 1 0 4 ) (≤10^4) (104) which is the number of PATers. The next line gives N distinct sizes of the hats, which are positive numbers no more than 1 0 5 10^5 105. The sizes correspond to the hats from bottom up on the stack. Finally in the last line, N distinct weights are given, correspond to the hat owners numbered from 1 to N. The weights are positive numbers no more than 1 0 6 10^6 106. All the numbers in a line are separated by spaces.

输出

For each test case, print in a line the indices of the hat owners in the order of picking up their hats. All the numbers must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.

思路

一样我来讲解一下,别看题目说的天花乱坠的,还说什么栈之类的,其实就是第一行给你一些不同的整数,把他们依次放到栈里面(也就是最后你要倒着读出来),这些数表示帽子的大小。第二行给你同样数目的一些数字,这些数字表示人的体重,我们依次从第一行倒着取一个数,这个数表示当前帽子的大小,通过所有帽子我们可以知道他是第几大的帽子,我们需要找到在人群中同样位次的那个人,例如:
帽子size: 10 5 100
人的体重:100 300 200
第一个帽子为100可以知道他是最大的数,排第一,我们发现对应的人的为体重为300的那个对应编号为2,所以输出2
所以我们可以给帽子大小排序(存标号),然后拍完需后存在排序后的标号,然后再根据之前的标号重新排序,这样还原回去后我们就可以获得每一个位置对应的那个排序标号了,体重也可以排序(存一开始标号),这样我们就可以获得了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stdlib.h>
using namespace std;
typedef struct node {
    
    
	int weight;
	int number;
}Per;
typedef struct Node {
    
    
	int si;
	int number;
}Hat;
Per per[110000];
Hat hat[110000];
int cun[110000];
bool cmp1(Hat a, Hat b)
{
    
    
	return a.si > b.si;
}
bool cmp2(Per a, Per b)
{
    
    
	return a.weight > b.weight;
}
bool cmp3(Hat a, Hat b)
{
    
    
	return cun[a.number] > cun[b.number];
}
int main()
{
    
    
	int N;
	cin >> N;
	for (int i = 0; i < N; i++)
	{
    
    
		cin >> hat[i].si;
		hat[i].number = i + 1;
	}
	for (int i = 0; i < N; i++)
	{
    
    
		cin >> per[i].weight;
		per[i].number = i + 1;
	}
	sort(hat, hat + N, cmp1);
	for (int i = 0; i < N; i++)
	{
    
    
		cun[i] = hat[i].number;
		hat[i].number = i;
	}
	sort(per, per + N, cmp2);
	sort(hat, hat + N, cmp3);
	for (int i = 0; i < N; i++)
	{
    
    
		printf("%d", per[hat[i].number].number);
		if (i < N - 1)
		{
    
    
			printf(" ");
		}
	}
	cout << endl;
}

第三题

题目描述

A playground is equipped with ball pits and tents connected by tunnels. Kids can crawl through the tunnels to meet their friends at a spot with a tent or a ball pit.
Now let’s mark each meeting spot (a tent or a ball pit) by a number. Assume that once a kid starts to explore the playground from any meeting spot, he/she will always choose the next destination with the smallest number, and he/she would never want to visit the same spot twice. Your job is to help the kids to find the best starting spot so they can explore as many spots as they can.

输入

Each input file contains one test case. For each case, the first line gives two positive integers N (≤100), the total number of spots, and M, the number of tunnels. Then M lines follow, each describes a tunnel by giving the indices of the spots (from 1 to N) at the two ends.

输出

Print in a line the best starting spot which leads to the maximum number of spots, and the number of spots a kid can explore. If the solution is not unique, output the one with the smallest index. There must be exactly 1 space between the two numbers, and there must be no extra space at the beginning or the end of the line.

思路

题目意思是给你一个图,现在你可以从任意一个位置出发,然后在走的时候不能回到已经经过的点,问你哪一个点出发可以经过最多的节点。
一开始看到N 100左右想到了用dfs结果超时GG。后来想了想这不是就是求最小路径变化,改求最大路径而已。。。用的dijiesitela算法,应该也可以用floryd算法吧

代码

#include<iostream>
#include<cstdio>
#include<stdlib.h>
#include<queue>
#include<vector>
using namespace std;
int graph[1000][1000] = {
    
     0 };
int cen[1000] = {
    
     0 };
int all_mmax = 0;
int N, M;
int dj(int f)
{
    
    
	int visit[1100] = {
    
     0 };
	int dp[1100] = {
    
     0 };
	int mmax = 0;
	fill(dp, dp+1000, -1);
	for (int i = 1; i <= N; i++)
	{
    
    
		if(graph[f][i]==1)
			dp[i] = 1;
	}
	visit[f] = 1;
	while(1)
	{
    
    
		int mmax = -1;
		int u=-1;
		for (int j = 1; j <= N; j++)
		{
    
    
			if (visit[j] == 0)
			{
    
    
				if (dp[j] > mmax)
				{
    
    
					mmax = dp[j];
					u = j;
				}
			}
		}
		if (u == -1)
		{
    
    
			break;
		}
		visit[u] = 1;
		for (int j = 1; j <= N; j++)
		{
    
    
			if (visit[j] == 0)
			{
    
    
				if (graph[u][j] == 1)
				{
    
    
					if (dp[j] < dp[u] + graph[u][j])
					{
    
    
						dp[j] = dp[u] + graph[u][j];
					}
				}
			}
		}
	}
	for (int i = 1; i <= N; i++)
	{
    
    
		if (mmax < dp[i])
		{
    
    
			mmax = dp[i];
		}
	}
	return mmax;
}
int main()
{
    
    
	
	cin >> N >> M;
	int ans;
	for (int i = 0; i < M; i++)
	{
    
    
		int a, b;
		cin >> a >> b;
		graph[a][b] = 1;
		graph[b][a] = 1;
	}
	ans = 1;
	for (int i = 1; i <= N; i++)
	{
    
    
		int now=dj(i);
		if (now > all_mmax)
		{
    
    
			all_mmax = now;
			ans = i;
		}
	}
	printf("%d %d\n", ans, all_mmax+1);
	
}

第四题

题目描述

A Sorted Cartesian tree is a tree of (key, priority) pairs. The tree is heap-ordered according to the priority values, and an inorder traversal gives the keys in sorted order. For example, given the pairs { (55, 8), (58, 15), (62, 3), (73, 4), (85, 1), (88, 5), (90, 12), (95, 10), (96, 18), (98, 6) }, the increasing min-heap Cartesian tree is shown by the figure.
Your job is to do level-order traversals on an increasing min-heap Cartesian tree.

输入

Each input file contains one test case. Each case starts from giving a positive integer N (≤30), and then N lines follow, each gives a pair in the format key priority. All the numbers are in the range of int.

输出

For each test case, print in the first line the level-order traversal key sequence and then in the next line the level-order traversal priority sequence of the min-heap Cartesian tree.
All the numbers in a line must be separated by exactly one space, and there must be no extra space at the beginning or the end of the line.

思路

就是这个树的节点包含两部分,一部分是key,一部分是priority,然后对于key来说,key从小到大排序后确定的是树的中序遍历,然后priority决定的是小根堆,因此我们就可以构建树。
怎么构建呢,首先根据key排序为
中序key:55 58 62 73 85 88 90 95 96 98
priority: 8 15 3 4 1 5 12 10 18 6
我们在构建树时,根据中序L和R中找到最小的priority为根,依次递归就行

代码

#include<iostream>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef struct node {
    
    
	int key;
	int pri;
}my;
typedef struct NODE {
    
    
	my k;
	struct NODE* left;
	struct NODE* right;
}Tree;
my in[100];
bool cmp(my a, my b)
{
    
    
	return a.key < b.key;
}
Tree* create(int inl, int inr)
{
    
    
	if (inl == inr)
	{
    
    
		Tree* p = (Tree*)malloc(sizeof(Tree));
		p->left = NULL;
		p->right = NULL;
		p->k = in[inl];
		return p;
	}
	if (inl > inr)
	{
    
    
		return NULL;
	}
	int mmin = in[inl].pri;
	int rootId = inl;
	for (int i = inl; i <= inr; i++)
	{
    
    
		if (in[i].pri < mmin)
		{
    
    
			mmin = in[i].pri;
			rootId = i;
		}
	}
	Tree* p = (Tree*)malloc(sizeof(Tree));
	p->k = in[rootId];
	p->left = create(inl, rootId - 1);
	p->right = create(rootId + 1, inr);
	return p;
}
int main()
{
    
    
	int N;
	cin >> N;
	for (int i = 0; i < N; i++)
	{
    
    
		cin >> in[i].key >> in[i].pri;
	}
	sort(in, in + N, cmp);
	Tree* head = create(0, N - 1);
	queue<Tree*> q;
	q.push(head);
	vector<int> v;
	vector<int> pr;
	while (!q.empty())
	{
    
    
		Tree* cur = q.front();
		q.pop();
		v.push_back(cur->k.key);
		pr.push_back(cur->k.pri);
		if (cur->left != NULL)
		{
    
    
			q.push(cur->left);
		}
		if (cur->right != NULL)
		{
    
    
			q.push(cur->right);
		}
	}
	for (int i = 0; i < N; i++)
	{
    
    
		printf("%d", v[i]);
		if (i < N - 1)
		{
    
    
			printf(" ");
		}
	}
	cout << endl;
	for (int i = 0; i < N; i++)
	{
    
    
		printf("%d", pr[i]);
		if (i < N - 1)
		{
    
    
			printf(" ");
		}
	}
	cout << endl;
}

总结

最后说说本次题总结吧,这次题目第一题算一个小坑点,其他题目都还好,基本都是基础算法的变种,难度的话,根pat提供的题集相比,我觉得这次在60%左右,应该还好,只是考试的话,会稍微感觉难一点。这次题目描述也比较多,英语薄弱的话可能有点吃力,再就是理解了,反正基本刷完所有题,我觉得过pat不算难,总之大家加油!这次没考好,下次过就行!!

猜你喜欢

转载自blog.csdn.net/qq_45478482/article/details/120251896