2021年 PAT(乙级)

7-1 好数 (15 分)

题目描述

好数是指由一对正整数 a<b 按照 a 2 + a b + b 2 a ^2+ab+b ^2 a2+ab+b2这个规则生成的数,a 和 b 就称为这个好数的源头。例如 91 就是一个好数,因为 5 2 + 5 × 6 + 6 2 = 91 5^2+5×6+6 ^2=91 52+5×6+62=91,于是数对(5,6)就是 91 的源头。而对于一个好数,其源头并不一定唯一,例如(1,9)就是 91 的另一个源头。

本题就要求你编写程序,判断一个给定的数字是否好,并且输出好数的所有源头。

输入格式:
输入在第一行给出一个不超过 100 的正整数 N,随后 N 行,每行给出一个不超过 1 0 4 10^4 104的正整数。

输出格式:
对于每一个输入的数字,如果其是好数,则首先在一行中输出 Yes,然后每行输出它的一个源头,格式为 a b,按 a 的递增顺序输出;否则在一行中输出 No和比该数大的最小的好数,其间以空格分隔,然后每行输出这个好数的一个源头,格式同上。

输入样例:
3
1
91
50

输出样例:
No 7
1 2
Yes
1 9
5 6
No 52
2 6

代码

利用常规方法(通过式子判断)模拟
#include <iostream>
#include <cstring>
#include <map>
using namespace std;

const int N = 1e4;
int n , k = 0;
pair<int , int> p[N];//利用pair存储
bool is_haoshu(int u)
{
	int f = 0;
	for(int i = 1 ; i * i < u ; ++i) {
		for(int j = i + 1 ; j * j < u ; ++j) {
			if(i * i + i * j + j * j == u) {
				f = 1;
				p[k].first  = i;
				p[k].second = j;
				++k;
			}
		}
	}
	if(f) {
		return true;
	} else {
		return false;
	}
}
void print()
{
	for(int i = 0 ; i < k ; ++i) {
		cout << p[i].first << " " << p[i].second << endl;
	}
	//初始化
 	memset(p , 0 , sizeof p);
	k = 0;
}
int main()
{
	cin >> n;
	while(n--) {
		int num;
		cin >> num;
		if(is_haoshu(num)) {
			cout << "Yes\n";
			print();
		} else {
			cout << "No ";
			for(int i = num + 1 ; ; ++i) {
				if(is_haoshu(i)) {
					cout << i << endl;
					print();
					break;
				}
			}
		}
	}
	return 0;
}
利用哈希表存储所有数的源头
#include<iostream>
#include<vector>
#include<unordered_map>
#include<set>

using namespace std;
typedef pair<int, int> PII;
int main()
{
	unordered_map<int, vector<PII>> hash;
	set<int> S;
	//存储
	for (int i = 1; i <= 100; i++) {
		for (int j = i + 1; j <= 100; j++) {
			int num = i * i + i * j + j * j;
			S.insert(num);
			hash[num].push_back({ i, j });
		}
	}
	int n; 
	cin >> n;
	for (int i = 0; i < n; i++) {
		int question;
		cin >> question;
		if (!S.count(question)) {//如果不存在
			question = *S.upper_bound(question);
			//*为解引用
			cout << "No" << ' ' << question << endl;
		}else {
			cout << "Yes" << endl;
		}
		for (auto& p : hash[question]) {
			cout << p.first << ' ' << p.second << endl;
		}
	}
	return 0;
}
解题思路
  1. 首先观察数据范围每个N都在 1 0 4 10^4 104以内,大致可以算一下对于最大的N假设它的源头是(i,j)均在60左右 所以用一个哈希表记录每个N可行的源头unordered_map<int, vector<PII>>,这样在处理每一个询问时可以直接查表输出N的所有源头同时因为预处理时是按照从小到大的顺序的,所有哈希表李的每个源头都是按题目要求排列好的。
  1. 若询问未在预处理的好数里,要返回离他最近的一个好数并输出其结果,可以用一个C++里的有序集合set ,使用二分函数upper_bound可以快速找到set中比询问大的第一个数。

7-2 数以类聚 (20 分)

题目描述

我们把所有各位数字的乘积相同的数归为一类。例如 1362 和 2332 就是同一类,因为 1×3×6×2=2×3×3×2。给定 N 个正整数,请你判断它们可以被归成多少不同的类?

输入格式:
输入在第一行给出一个正整数 N ( ≤ 1 0 5 ) (≤10 ^5 ) 105,第二行给出 N 个不超过 1 0 7 10 ^7 107的正整数,数字间以空格分隔。

输出格式:
在一行中输出 N 个给定的整数可以归类的数量、以及规模最大的类中最小的乘积。数字间以一个空格分隔。

输入样例:
10
1234 98 329 9552 47621 8862 5539 2333 5365 463

输出样例:
7 54

样例说明:
10 个给定数字对应的各位数字乘积依次为:24、72、54、450、336、768、675、54、450、72。所以一共有 7 个不同的种类,即:24、72、54、450、336、768、675。

其中规模最大的有 2 个 54、2 个 72、2 个 450。即这 3 个种类都分别对应了 2 个数字,在规模相等、都是最大的情况下,我们输出最小的乘积 54。

代码

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n;
    cin >> n;
    multiset <int> s;//从小到大存储其乘积数
    set<int> s0;//去重,计算归类数量
    multimap<int , int , greater<int>> m;//从大到小存储次数(键)和乘积(值)
    while(n--) {
        int num;
        cin >> num;
        int t = 1;
        while(num) {
            t *= num % 10;
            num /= 10;
        }
        s.insert(t);
		s0.insert(t);
    }
    for(auto it = s.begin() ; it != s.end() ; ++it) {
  		m.insert(make_pair(s.count(*it) ,*it));
	}
	cout << s0.size() << " " << m.begin()->second;
    return 0;
}
思路
  1. 利用排序容器将值进行排序(set乘积排序 , map 次数排序)
  2. 先利用multiset容器插入乘积
  3. 在利用mmultimap容器插入乘积的个数(set中s.count函数)和乘积
  4. 再利用set容器去重计算归类乘积数

7-3 自定义判题程序 (20 分)

题目描述

在每次允许插入、删除、修改一个字符的前提下,用最少的动作把一个字符串变成另一个字符串,是一道著名的可以用动态规划解决的问题。但判题的麻烦之处在于,虽然最小代价是唯一的,但变换方法却是不唯一的。例如把 PAT 变成 PTA 最少需要 2 步,可以保持第 1 个字母不变,修改后面 2 个字母,也可以保持第 1、2 个字母不变,在 A 前面插入 T,后面删除 T。由于拼题 A 系统的默认判题程序只能通过比对输出文件来判断对错,对这种正确答案输出不唯一的题目就不能处理了,需要出题者额外编写一个自定义判题程序来解决问题。

本题就请你编写这个自定义判题程序,读入两个字符串和用户程序产生的输出结果,判断他们的程序输出是否正确。

输入格式:
输入首先在前两行分别给出两个不超过 1000 个字符、以回车结束的非空字符串,第 1 行对应初始字符串,第 2 行对应目标字符串。

随后一行给出一个正整数 N(≤100),为需要判断的提交数。

接下来是 N 个提交的输出结果,每个结果占 2 行:第 1 行给出一个整数 K(不超出 32 位 int 的范围),为用户输出的动作数;第 2 行顺次描述对初始字符串的每个字符所做的操作:

如果这个字符不变,则在对应位置输出 0
如果这个字符被删除,则在对应位置输出 1
如果这个字符被改变,则在对应位置输出 2
如果这个字符前面或者后面插入了一个字符,则在插入的位置输出 3
注意我们要求用户提交的行首尾和数字间均无空格,所以如果有多余空格应判为错误。

题目保证这个操作序列不为空。

输出格式:
对每个正确的提交,在一行中输出 AC;否则输出 WA

注意:这里并不要求你会用动态规划求出最优解。所以对“正确提交”的判断,并不以动态规划求出的最优解为根据! 对于用户输出的 K,如果其操作序列的确给出了 K 步操作并可以完成字符串的变换,则称为一个“可行解”。所谓“正确提交”,是指所有提交的可行解中的最优解。

输入样例:
This is a test.
Tom is a cat.
6
8
02330001100022100
8
11113330000001113300
6
022100000012200
5
033310000000200
6
0 2 2 1 000000 1 2 2 00
6
012200000022100

输出样例:
WA
WA
AC
WA
WA
AC

代码

#include <bits/stdc++.h>

using namespace std;

int main()
{
	string s1 , s2 ,s0;
	getline(cin , s1);
	getline(cin , s2);
	int t ,k[11000] , maxx = 0x3f3f3f3f;
	cin >> t;
	for(int kk = 0 ; kk < t ; ++kk) {
		int n;
		cin >> n;
		getchar();
		string c;
		getline(cin , s0);
		int cnt = 0 , j = 0 , f = 0;
		for(int i = 0 ; i < s0.size() ; ++i) {
			if(s0[i] == '0') {
				c += s1[j];
				++j;
			} else if(s0[i] == '1') {
				++cnt;//删除无需处理,自动加1
				++j;
			} else if(s0[i] == '2') {
				c += '#';
				++cnt;
				++j;
			} else if(s0[i] == '3') {
				c += "#";
				++cnt;
			} else { //包括空格
   				f = 1;
			}
		}
  		if(c.size() != s2.size() || cnt != n) {
			f  = 1;
		}
		for(int i = 0 ; i < s2.size() ; ++i) {
			if(c[i] == s2[i] || c[i] == '#') {
				continue;
			} else {
				f = 1;
			}
		}
		if(!f) {
			k[kk] = n;
   			maxx = min(maxx , n);//获得最小步数
		} else {
			k[kk] = -1;
		}
	}
	for(int i = 0 ; i < t ; ++i) {
		if(k[i] == maxx) {
			cout << "AC\n";
		} else {
			cout << "WA\n";
		}
	}
    return 0;
}
思路
  1. 输入字符串的长度只能等于目标字符串的长度,并且其1,2,3操作的总和数等于输入的动作数
  2. 输入的字
  3. 符串只能含有0,1,2,3
  4. 在分析操作时,重新定义一个空字符串,对这个空字符串进行操作

7-4 数组与链表 (20 分)

题目描述

让我们来设计这样一种数组与链表结合的整数存储的结构 A:
这种结构首先初始化一个长度为 L 0 L_0 L0的整型数组 A 0 A_0 A0,返回给用户使用。当用户访问第 i 个元素 A[i] 的时候,如果 0 ≤ i < L 0 0 ≤ i < L_0 0i<L0,则 A[i] 对应 A 0 A_0 A0[i],系统就返回 h 0 h_0 h0​ + i × sizeof(int) 作为要访问的地址,其中 h 0 h_0 h0是数组 A 0 A_0 A0的起始位置,sizeof(int) 是数组元素的大小,这里元素就是 int 型,占 4 个字节。
当用户访问越界时(即 i ≥ L 0 i ≥ L_0 iL0),系统将另外开辟一个长度为 L 1 L_1 L1的数组 A 1 A_1 A1。此时 A[i] 对应 A 1 A_1 A1[j](这里 i 和 j 之间的映射关系留给你去推导)。如果 0 ≤ j < L 1 0≤j<L_1 0j<L1,则返回 h 1 + j × s i z e o f ( i n t ) h_1+j × sizeof(int) h1+j×sizeof(int) 作为要访问的地址,其中 h 1 h_1 h1是数组 A 1 A_1 A1的起始位置。当 A 1 [ j ] A_1[j] A1[j] 继续越界时,系统就按照上述规则继续开辟另一个长度为 L 2 ​ 的 数 组 A 2 L_2​ 的数组 A_2 L2A2,并以此类推。

本题就请你实现这个系统功能,为用户的任何一次访问返回对应元素的地址。

输入格式:
输入第一行给出两个正整数 N ( ≤ 1 0 4 ) (≤ 10 ^ 4) 104和 K$(≤ 1 0 3 ) 10 ^ 3) 103,分别为最多允许开出的数组个数、以及用户访问的次数。

此后 N 行,每行给出两个正整数,分别是一个数组的初始地址( ≤ 1 0 7 ≤10 ^ 7 107 )和长度(≤ 100),其间以空格分隔。题目保证这些数组占据的空间无重叠。

最后一行顺序给出 K 个用户访问的数组下标,为区间 [ 0 , 2 20 ] [0, 2 ^ {20}] [0,220] 内的整数。

输出格式:
对每个用户访问,在一行中输出对应的地址。但如果用户的访问超出了 N 个数组的存储范围,则这个访问是非法的,要输出 Illegal Access,并且对这个访问不采取任何处理。

最后一行请输出上述过程中一共创建了多少个数组。

输入样例:
6 7
2048 5
128 6
4016 10
1024 7
3072 12
9332 10
2 12 25 50 28 8 39

输出样例:
2056
4020
1040
Illegal Access
3072
140
3116
5

代码

#include <iostream>
using namespace std;

const int N = 1e4;
struct array {
    int h0  , l , l0 = 0;
}a[N];
int main()
{
    int n , k , l_sum = 0;
    cin >> n >> k;
    for(int i = 0 ; i < n ; ++i) {
        cin >> a[i].h0 >> a[i].l;
        a[i].l0 += a[i].l + a[i - 1].l0;
        l_sum += a[i].l;
    }
    int Max = 1;//emmmm最小的就是1
    while(k--) {
		int num;
		cin >> num;
		if(num > l_sum - 1) {
			cout << "Illegal Access\n";
			continue;
		}
		for(int i = 0 ; i < n ; ++i) {
			if(num >= a[i - 1].l0 && num < a[i].l0) {
				cout << a[i].h0 + (num - a[i - 1].l0) * sizeof(int) << endl;
				Max = max(Max , i + 1);
				break;
			}
		}
	}
	cout << Max<< endl;
    return 0;
}

7-5 取帽子 (25 分)

题目描述

请添加图片描述
拼题er们觉得戴帽子会令自己看上去很帅,所以他们不管到哪里都会戴着帽子。有一天他们去到一家餐厅,服务员把他们的帽子收集了堆起来保管。当大家要离开的时候,发现帽子被像上图那样摞起来了。于是你的任务就是帮他们排好队,使得每个人都能按顺序顺利取到自己的帽子。

已知每顶帽子的大小都不相同,并且帽子的尺寸跟帽子主人的体重有关 —— 越重的人戴的帽子就越大。

输入格式:
输入第一行给出一个正整数 N ( ≤ 1 0 4 (≤10^4 (104),为拼题er的人数。随后一行给出 N 个不同的帽子尺寸,为不超过 1 0 5 10 ^5 105的正整数,顺序是从帽子堆的底部向上给出。最后一行给出 N 个不同的体重,顺序对应编号从 1 到 N 的拼题er。体重是不超过 1 0 6 10^6 106的正整数。一行中的数字以空格分隔。

输出格式:
在一行中按照取帽子的顺序输出帽子主人的编号。数字间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:
10
12 19 13 11 15 18 17 14 16 20
67 90 180 98 87 105 76 88 150 124

输出样例:
3 4 8 6 10 2 1 5 9 7

样例说明:
第一顶帽子的尺寸是最大的 20,所以对应第 3 个人的最大体重 180,于是第 3 个人排在最前面。

第二顶帽子的尺寸是第 6 小的 16,对应第 6 小的体重 98,是第 4 个人,于是第 4 个人下一个走。

以此类推。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4;
int a[N] ,b[N] , c[N];
int main()
{
	int n;
	cin >> n;
	map<int , int> m1;
	for(int i = 1 ; i <= n ; ++i) {
		cin >> a[i];
		c[i] = a[i];
	}
	sort(c + 1 , c + n + 1);
	for(int i = 1 ; i <= n ; ++i) {
  		m1[c[i]] = i;
	}
  	map<int , int> m2;
  	int j = 0;
	for(int i = 1 ; i <= n ; ++i) {
		cin >> b[i];
  		m2[b[i]]
	}
	sort(b + 1 , b + n + 1);
 	for(int i = n ; i >= 1 ; --i) {
		cout << m2[b[m1[a[i]]]] << " \n"[i == 1];
	}
	return 0;
}
思路
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PAT乙级1009题是一个关于字符串处理的题目。根据题目要求,我们需要将输入的字符串按照单词的逆序输出。根据提供的引用内容,我们可以看到有三种不同的解法。 引用\[1\]和引用\[2\]是两个相似的解法,使用了字符串处理函数strchr和strrchr来定位空格字符,并将字符串分割成单词。然后通过循环输出单词,最后输出剩余的最后一个单词。 引用\[3\]是另一种解法,使用了二维数组存储每个单词。通过循环读取输入的字符串,直到遇到换行符为止。然后通过倒序循环输出每个单词。 根据题目要求,你可以选择其中一种解法来完成PAT乙级1009题。 #### 引用[.reference_title] - *1* [PAT考试乙级1009(C语言实现)](https://blog.csdn.net/JeffreyDDD/article/details/78395267)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [PAT乙级1009(C语言实现)](https://blog.csdn.net/weixin_62870950/article/details/124934829)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [PAT乙级测试题1009(C语言实现)](https://blog.csdn.net/weixin_45947840/article/details/105943475)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值