PAT甲级_2022春(92)

总结

第五次模考,连着考了三场,做到7-4的时候已经凌晨1点脑子瓦特了,最终92。这也是去年刷了20道题后第一次报名考的卷子,那次50分。前3道题偏简单,7-4BFS没AC还是写少了。
在这里插入图片描述

第一题

12min

题意

给定问题数n、阈值t和测试者数量k。然后给出k个测试者的回答内容,以字符串的形式,每个回答对应于一个从a到h的字母。然后根据给定的一系列限定确定这个回答的分数,根据分数打分。

思路

  • 常规模拟,先接收n、t、k。
  • 然后循环k次,每次设置cnt记录最终得分,最后输出,大于k的额外输出!!!

题解

#include<bits/stdc++.h>
using namespace std;
int n, t, k;
int main(){
	cin>>n>>t>>k;
	while(k --){
		string input; cin>>input;
		int cnt = 0, con = 1, sam = 1;
		if(input[0] == 'f') cnt -= 2;
		if(input[n - 1] == 'a') cnt --;
		for(int i = 1; i < n; i ++){
			if((input[i] == 'e' || input[i] == 'h') && input[i - 1] == 'a') cnt -= 4;
			if(input[i] - input[i - 1] == 1) con++;
			else{
				if(con > 3) cnt += 5;
				con = 1;
			}
			if(input[i] == input[i - 1]) sam ++;
			else{
				if(sam > 5) cnt += 3;
				sam = 1;
			}
		}
		if(con > 3) cnt += 5;
		if(sam > 5) cnt += 3;
		cout<<cnt;
		if(cnt > t) cout<<"!!!";
		puts("");
	}
	return 0;
}

第二题

14min

题意

给定输入数量n和需要输出的数量k。然后给n个数字,排序从大到小输出最大的k个数字。

思路

  • 一眼用优先队列,然后MLE了,因为2048KB的上限而有最多1E6个数字 - 即4MB
  • 然后感觉优先队列不好删除较小的元素,就改用set。这里想法不对,如果采用小端优先队列,比较队头与输入元素的大小然后决定是否要进行出队后入队的操作,也是可行的。
  • 采用set后TLE,因为1E6的输入规模导致cin和scanf时间差较大,这里被cin卡了
  • 改为scanf后一个测试点WA,显然是有重复元素的原因,改成multiset后就AC了。

小结

  • 当输出数据达到一定规模后(1E6),输入必须scanf,这里时间被卡了。
  • 需要动态调整容器大小保持在k,2048KB的上限卡了空间。

题解(AC)

#include<bits/stdc++.h>
using namespace std;
int n, t, k;
multiset<int> ans;
deque<int> out;
int main(){
	cin>>n>>k;
	for(int i = 0; i < n; i ++){
		scanf("%d", &t);
		ans.insert(t);
		if(ans.size() > k) ans.erase(ans.begin());
	}
	for(auto i : ans) out.push_front(i);
	for(int i = 0; i < out.size(); i ++){
		printf("%d", out[i]);
		if(i != out.size() - 1) printf(" ");
	}
	return 0;
}

题解 - 第一次(MLE)

#include<bits/stdc++.h>
using namespace std;
int n, t, k, a[1000001];
int main(){
	cin>>n>>k;
	priority_queue<int> que;
	for(int i = 0; i < n; i ++){
		scanf("%d", &a[i]);
		que.push(a[i]);
	}
	for(int i = 0; i < k; i ++){
		printf("%d", que.top());
		if(i != k - 1 && que.size() > 1) printf(" ");
		que.pop();
		if(!que.size())break;
	}
	return 0;
}

题解 - 优先队列 - 待测试

#include<bits/stdc++.h>
using namespace std;
int n, t, k, a[1000001];
int main(){
	cin>>n>>k;
	priority_queue<int, vector<int>, greater<int>> que;
	for(int i = 0; i < n; i ++){
		scanf("%d", &a[i]);
		if(que.size() < k) que.push(a[i]);
		else{
			if(a[i] > que.top()){
				que.pop();
				que.push(a[i]);
			}
		}
	}
	deque<int> ans;
	while(que.size()){
		ans.push_front(que.top());
		que.pop();
	}
	for(int i = 0; i < ans.size(); i ++) printf("%d%c", ans[i], i == ans.size() - 1 ? '\n': ' ');
	return 0;
}

第三题

16min

题意

给出数组长度n,然后给出顺序的n个数字,按照堆的方式(层序遍历,下标1开始)构成树,即2i、2i+1为i的孩子,如果对应值为-1说明为空。判断该树是否是BST,并写出给出树的中序遍历序列。

思路

  • 根据堆的性质,常规写出构造树函数mt(int p)。
  • 构造好后直接inorder函数遍历即可获得中序遍历序列。
  • 然后顺序访问下标1-n/2的节点,如果存在并且有左右孩子,写出求左子树的最大值和右子树的最小值的函数,对比根结点的值判断是否不满足BST的特性,用flag记录。
  • 这里看了一些大佬的解法是判断中序序列有序,但是该题对于BST的定义是左子树的结点值一定要小于根的值,故而认为测试点卡的不够科学,形如1 1 1的树是过不了测试点的。

题解

#include<bits/stdc++.h>
using namespace std;
int n, level[1001];
vector<int> in;
struct node{
	int k;
	struct node*l, *r;
}; 
node* mt(int p){
	if(p > n || level[p] == -1) return NULL;
	node * t = (node*)malloc(sizeof(node));
	t->k = level[p];
	t->l = mt(p * 2);
	t->r = mt(p * 2 + 1);
	return t;
}
bool flag = true;
int get_max(int t){
	int tmp = level[t];
	queue<int> que;
	que.push(t);
	while(que.size()){
		int tar = que.front();
		tmp = max(level[tar], tmp);
		que.pop();
		if(tar * 2 <= n && level[tar * 2] != -1) que.push(tar * 2);
		if(tar * 2 + 1 <= n && level[tar * 2 + 1] != -1) que.push(tar * 2 + 1);
	}
	return tmp;
}
int get_min(int t){
	int tmp = level[t];
	queue<int> que;
	que.push(t);
	while(que.size()){
		int tar = que.front();
		tmp = min(level[tar], tmp);
		que.pop();
		if(tar * 2 <= n && level[tar * 2] != -1) que.push(tar * 2);
		if(tar * 2 + 1 <= n && level[tar * 2 + 1] != -1) que.push(tar * 2 + 1);
	}
	return tmp;
}
bool test(){
	for(int i = 1; i * 2 <= n; i ++){
		if(level[i] == -1)continue;
		int tar = i;
		if(level[i * 2] != -1 && level[tar] <= get_max(i * 2)){
			return false;
		}
		if(i * 2 + 1 <= n && level[i * 2 + 1] != -1 && level[tar] > get_min(i * 2 + 1)){
			return false;
		}
	}
	return true;
}
void inorder(node* t){
	if(t->l){
		inorder(t->l);
		if(t->l->k >= t->k) flag = false;
	}
	in.push_back(t->k);
	if(t->r){
		inorder(t->r);
		if(t->r->k < t->k) flag = false;
	}
}
int main(){
	cin>>n;
	for(int i = 1; i <= n; i ++) cin>>level[i];
	node * t = mt(1);
	inorder(t);
	puts(test() ? "YES" : "NO");
	for(int i = 0 ; i < in.size(); i ++){
		if(i) cout<<' ';
		cout<<in[i];
	}
	return 0;
}

第四题

140min

题意

这应该是见过的最难理解的题目了,英语不好,看着样例理解题目哈哈哈TToTT。
首先给出图的长宽n,m。
然后给出图的模样,包含OX#三种元素。O和X表示可到达,#表示被阻断。X表示目的地。
然后给出一个贪心算法,要求以此求出一个序列,所有O都可以通过这个序列到达X。
贪心算法如下:

  • 首先找到离X最远的O,将从该O到X的子序列输出,并将这个子序列的行走路线应用到所有O上面,然后有部分O能到达X有部分O到不了X。
  • 到不了X的部分O会到达?,取离X最远的一个?,将该子序列输出,并应用到所有?上面,然后有部分?能到达X有部分?到不了X。
  • 重复如上操作直到所有点都能到达X。

思路

  • 首先接收n、m,用char g[101][101]记下来。
  • 然后通过BFS记录每个结点到达X的路径,记入string road[101][101]
  • 遍历road找到最大的一条路记入string substr并输出
  • 然后将substr应用到所有O,没到X的把终点记入vector<pair<int, int>> rec
  • 从rec中找到到达X最远的元素的路径记入string substr并输出
  • 将这条路径应用到所有rec中的元素,如果没到X的把终点记入vector<pair<int, int>> rec2.然后rec = rec2.
  • 重复上两步,直到出循环时rec大小为0.

小结

  • 太过复杂的题目不要发怵,没用的。一点点梳理,像上面这样列出详细过程,然后实现,其实耗时也不会超过30min,重写了一遍如下,能过样例,但不知道能不能AC。

题解 - 待测试

#include<bits/stdc++.h>
using namespace std;
const int N = 104;
int n, m, sx, sy;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, -1, 0, 1};
char g[N][N];
string road[N][N];
bool st[N][N];
int main(){
	cin>>n>>m;
	getchar();
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= m; j ++){
			scanf("%c", &g[i][j]);
			if(g[i][j] == 'X') sx = i, sy = j;
		}
		getchar();
	}
	queue<pair<int, int>> que;
	que.push({sx, sy});
	while(que.size()){
		auto tar = que.front(); que.pop();
		if(st[tar.first][tar.second]) continue;
		st[tar.first][tar.second] = true;
		for(int i = 0; i < 4; i ++){
			int tx = tar.first + dx[i], ty = tar.second + dy[i];
			if(tx < 1 || tx > n || ty < 1 || ty > m || g[tx][ty] == '#') continue;
			if(road[tx][ty] == "") road[tx][ty] = to_string(i) + road[tar.first][tar.second];
			else if(road[tx][ty].size() == (to_string(i) + road[tar.first][tar.second]).size())
				road[tx][ty] = min(road[tx][ty], to_string(i) + road[tar.first][tar.second]);
			que.push({tx, ty});
		}
	}
	string substr;
	pair<int, int> ptr;
	set<pair<int, int>> rec, rec2;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= m; j ++){
			if(g[i][j] == 'O'){
				rec.insert({i, j});
				if(substr.size() < road[i][j].size()){
					substr = road[i][j];
					ptr = {i, j};
				}
				else if(substr.size() == road[i][j].size() && substr > road[i][j]){
					substr = road[i][j];
					ptr = {i, j};
				} 
			}
		}
	}
	while(rec.size()){
		rec.erase(ptr);
		cout<<substr;
		rec2.clear();
		for(auto tar : rec){
			int tx = tar.first, ty = tar.second;
			bool flag = false;
			for(int k = 0; k < substr.size(); k ++){
				tx -= dx[substr[k] - '0'], ty -= dy[substr[k] - '0'];
				if(tx < 1 || tx > n || ty < 1 || ty > m || g[tx][ty] == '#'){
					tx += dx[substr[k] - '0'], ty += dy[substr[k] - '0'];
					continue;
				}
				if(tx == sx && ty == sy){
					flag = true;
					break;	
				} 
			}
			if(!flag) rec2.insert({tx, ty}); 
		}
		substr = "";
		for(auto tar : rec2){
			if(substr.size() < road[tar.first][tar.second].size()){
				substr = road[tar.first][tar.second];
				ptr = {tar.first, tar.second};
			}
			else if(substr.size() == road[tar.first][tar.second].size() && substr > road[tar.first][tar.second]){
				substr = road[tar.first][tar.second];
				ptr = {tar.first, tar.second};
			} 			
		}
		rec = rec2;
	}
	return 0;
}

7-1 Simple Lie Detection

lie.jpg

Lie detection usually uses a set of prepared questions to ask the testee, and the result is obtained by analyzing the testee’s reactions. The more advanced technology uses a polygraph (测谎仪) to monitor the physical activities of the testee. Our simple polygraph here is to make a judgment by analyzing the characteristics of the answers to the questions.

First, we ask the testee to complete N multiple choice questions, each with a single answer. Each question has 8 options, which are represented by the lowercase English letters a-h. Then we can obtain a string of length N, consisting of only the lowercase English letters a-h. Score each string, and those whose score exceeds a certain threshold (阈值) T are judged as “suspected liars”. The scoring rules are as follows:

  • the string starts with an f has its score −2;

  • the string ends with an a has its score −1;

  • for every longest segment of answeres where the same letter is chosen for consecutive questions, if the segment length is larger than 5, the score is to +3;

  • if an a is immediately followed by e or h, the score is to −4;

  • for every longest segment of answeres where consecutively increasing letters are chosen to answer consecutive questions (such as abcd or defgh), if the segment length is larger than 3, the score is to +5.

Your job is to score the answers and make a judgement.

Input Specification:

Each input file contains one test case. For each case, the first line gives 3 positive integers N (6≤N≤100), the number of questions; T (≤100), the threshold for judging a liar; and K (≤100), the number of testees.

Then K lines follow, each gives the string of answers of a testee.

Output Specification:

For each testee, print in a line the total score of his/her answers. If the score exceeds the threshold, print !!! after the score.

Sample Input:

12 1 6
fghaebcdeddd
ahhhhhhgbaaa
cdefffffffff
fffffghecaaa
feeeeeeeegcb
aaaaaabbbbbb

Sample Output:

-1
-2
8!!!
-3
1
6!!!

7-2 The First K Largest Numbers

The task is simple: find the first K largest numbers from a given sequence of N integers, and output them in descending order.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers N (≤106) and K (≤5). Then N integer keys (in the range [−230,230]) are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in descending order the Kth largest numbers.

All the numbers in a line must be separated by a space, and there must be no extra space at the beginning or the end of the line.

Sample Input 1:

10 4 
40 25 60 -15 30 -21 80 -1 -5 27

Sample Output 1:

80 60 40 30

Sample Input 2:

4 5 
23 -17 99 1

Sample Output 2:

99 23 1 -17

7-3 Is It A Binary Search Tree - Again

A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:

  • The left subtree of a node contains only nodes with keys less than the node’s key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
  • Both the left and right subtrees must also be binary search trees.

A binary tree with positive keys can be represented by an array, which stores the keys in level-order as in a complete tree, with all the NULL nodes represented by −1. For example, the following tree is stored in an array as { 40, 25, 60, -1, 30, -1, 80, -1, -1, 27 }.

bst1.png

Now given a sequence of integers in an array, you are supposed to tell if it corresponds to a BST, and output its inorder traversal sequence.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (≤1000). Then N integer keys (in the range (0, 100000)) are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, first print in a line YES if the sequence does correspond to a BST, or NO if not. Then print in the next line the inorder traversal sequence of that tree. It is guaranteed that the tree is non-empty.

All the numbers in a line must be separated by a space, and there must be no extra space at the beginning or the end of the line.

Sample Input 1:

10
40 25 60 -1 30 -1 80 -1 -1 27

Sample Output 1:

YES
25 27 30 40 60 80

Sample Input 2:

11
40 50 60 -1 30 -1 -1 -1 -1 -1 35

Sample Output 2:

NO
50 30 35 40 60

7-4 The Rescue

rescue.png

When a group of hikers get lost in a forest and call the rescue team, the team leader would send the hikers a sequence of instructions. By following these instructions, the hikers can always move to a spot that the rescue team can reach, no matter where their original location was. Your job is to generate such a sequence for each given map.

A map is a rectangular(矩形) area consists of n×m unit square areas. There is alway one square X that is marked to be the rescue spot. Some of the areas are blocked and marked to be #, meaning that the hikers cannot enter this block. We assume that the boundaries of the map are all blocked.

An instruction is an integer that represents a direction: 0 for North, 1 for East, 2 for South, and 3 for West. For example, the sequence of instructions 3001 tells the hikers to move toward West and enter the neighboring area first, then head toward North and cross two units, and finally move toward East into the neighboring area. If the destination area is blocked, the hikers must stay in the current area and wait for the next instruction. The sequence you generate must be able to direct the hikers to move into X no matter where they were in that map. Once they arrive at X, they will ignore the rest of the instructions.

There are many different ways of generating the sequence. Here we design a greedy algorithm, hoping to generate a not-too-long sequence. The algorithm works as the following:

  • Step 1: find the shortest paths from X to every other areas which the hikers might be in, and pick the furthest area A.
  • Step 2: generate sequence s for directing from A to X along the shortest path.
  • Step 3: update the map according to s – that is, mark all the possible areas that the hikers might be in after following s.
  • Step 4: if X is the only possible area that contains the hikers, stop; else goto Step 1.

The final sequence can be obtained by concatenating all the s’ generated in order.

Notice that while the shortest path might not be unique, you are supposed to output the smallest sequence. Sequence a1​,a2​,⋯,an​ is smaller than sequence b1​,b2​,⋯,bn​ if ther exists 1≤k≤n so that ai​=bi​ for all i<k, and ak​<bk​.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive numbers 3≤n,m≤100. Then n lines follow, each contains m characters to represent the map. The rescue spot is X, a block is #, and O represents an open area.

Output Specification:

Output in a line the sequence of instructions. There must be no space between the numbers, nor at the beginning or the end of the line.

It is guaranteed that the solution exists.

Sample Input:

4 5
O#OOO
OOXOO
OO##O
OOO#O

Sample Output:

0011300121133

Hint:

During the 1st round, there are 3 candidates for A, as shown below:

O#OOO
OOXOO
OO##O
AOA#A

To direct them to X with the smallest sequence, we must choose the one at the lower-left corner, with the sequence 0011. Since at the very beginning, the hikers might be in any of the open areas, we apply 0011 to every open area, and obtain a map as shown below:

?#OO?
OOXO?
OO##O
OO?#O

where ? means that currently it is a possible position of the hikers. Now clearly we must pick the ? in the last row to be the next A, and direct it to X with 3001. After applying this sequence to other areas marked by ?, we update the map as the following:

?#OO?
OOXOO
OO##O
OOO#O

Now both ?'s have the same path length to X. We pick the upper-left corner to be A since it has the smaller sequence 211. The map is updated as the following:

O#OOO
OOXO?
OO##O
OOO#O

Finally apply 33, we can direct the last ? to X.

Hence the output sequence is 0011 3001 211 33.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值