2021年秋季PAT乙级(复盘)

7-1 好数 (15 分)
好数是指由一对正整数 a<b 按照 a ^2+ab+b ^2这个规则生成的数,a 和 b 就称为这个好数的源头。例如 91 就是一个好数,因为 5 ^2+5×6+6 ^2=91,于是数对(5,6)就是 91 的源头。而对于一个好数,其源头并不一定唯一,例如(1,9)就是 91 的另一个源头。
本题就要求你编写程序,判断一个给定的数字是否好,并且输出好数的所有源头。

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

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

输入样例:
3
1
91
50
输出样例:
No 7
1 2
Yes
1 9
5 6
No 52
2 6

#include<bits/stdc++.h>
using namespace std;

int m[110];
int n;
vector<int>v;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    cin>>n;
    
    for(int i=0;i<n;i++)
    cin>>m[i];
    
    for(int a=1;a<=100;a++)
    {
        for(int b=a+1;b<=100;b++)
        {
            v.push_back(a*a+a*b+b*b);
        }
    }
    
    sort(v.begin(),v.end());
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<v.size();j++)
        {
            if(m[i]==v[j])
            {
                cout<<"Yes"<<endl;
                for(int a=1;a<=sqrt(m[i])+5;a++)
                {
                    for(int b=a+1;b<=sqrt(m[i])+5;b++)
                    {
                        if(a*a+a*b+b*b==m[i])
                            cout<<a<<" "<<b<<endl;
                    }
                }
                break;
            }
            else if(v[j]>m[i])
            {
                cout<<"No "<<v[j]<<endl;
                for(int a=1;a<=sqrt(v[j])+5;a++)
                {
                    for(int b=a+1;b<=sqrt(v[j])+5;b++)
                    {
                        if(a*a+a*b+b*b==v[j])
                            cout<<a<<" "<<b<<endl;
                    }
                }
                break;
            }
        }
    }
    return 0;
}

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

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

输出格式:
在一行中输出 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<iostream>
#include<vector>
#include<set>
#include<map>
using namespace std;

map<int,int>mp;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    int n;
    cin>>n;
    
    int x;
    for(int i=0;i<n;i++)
    {
        cin>>x;
        int sum=1;
        int temp=x;
        while(temp)
        {
            sum=sum*(temp%10);
            temp=temp/10;
        }
       mp[sum]++;
    }
    
    cout<<mp.size()<<" ";
    int ans=0;
    for(auto it=mp.begin();it!=mp.end();it++)
    {
        if(it->second>ans)
        ans=it->second;
    }
    
    for(auto it=mp.begin();it!=mp.end();it++)
    {
        if(ans==it->second)
        {
            cout<<it->first;
            break;
        }
    }
    
    cout<<endl; 
    return 0;
}

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 步操作并可以完成字符串的变换,则称为一个“可行解”。所谓“正确提交”,是指所有提交的可行解中的最优解。

#include <bits/stdc++.h>
using namespace std;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t, k[11000];//t:所需测评数量,k[]:存放每组答案的判题结果
	string a, b, s;//分别存放原字符串,
	int minn=9999999;//存放最小正确答案,初始值
	getline(cin,a);
	getline(cin,b);//务必使用getline读入
	cin >> t;
 
	for(int kk=0;kk<t;kk++)
	{
		int n, j=0, f=0, cnt=0;//n:读取操作总数,j:用于模拟当前处理的字符位置,f:记录明显的错误,一旦变为1则代表WA了,cnt:记录当前已经操作了多少次
		cin >> n;
		string c;//模拟被生成的字符串
		getchar();//消除换行
		getline(cin,s);
		for(int i=0;i<s.size();i++)
		{
			if(s[i]=='0')//该字符不变,加入字符串c,j指向下一位,cnt不变
			{
				c+=a[j];
				j++;
			}
			else if(s[i]=='1')//该字符删除,j直接指向下一位,操作步骤cnt++
			{
				j++;
                cnt++;
			}
			else if(s[i]=='2')//该字符改变,我们此处认为'^'为万能字符,后续进行判断时直接代表该字符正确
			{				  //j指向下一位,操作步骤cnt++
				c+='^';
				j++;
                cnt++;
			}
			else if(s[i]=='3')//直接添加,cnt++,j仍然指向原位
			{
				c+='^';
                cnt++;
			}
			else f=1;//出现了0,1,2,3以外的字符,对该组数据直接判WA
		}
 
		if(c.size()!=b.size()||cnt!=n)//目标字符串与原字符串字数个数不等,或实际操作数与读入不同
			f=1;
		
		for(int i=0;i<b.size();i++)//遍历对比两字符数组
		{
			if(c[i]==b[i]||c[i]=='^') continue;//字符相同或被标记为万能字符,判断下一个
			else f=1;//出现错误,直接判WA
		}
		
		if(f==0)
		{
			k[kk]=n;
			if(n<minn) minn=n;//记录操作数的最小值
		}
		else
			k[kk]=-1;//记录错误
	}
 
	for(int i=0;i<t;i++)
	{
		if(k[i]==minn) cout<<"AC"<<endl;//恰好等于最小值的为AC
		else cout<<"WA"<<endl;//否则为WA
	}
       
    //system("pause");
	return 0;
}

7-4 数组与链表 (20 分)
让我们来设计这样一种数组与链表结合的整数存储的结构 A:这种结构首先初始化一个长度为 L0的整型数组 A0,返回给用户使用。当用户访问第 i 个元素 A[i] 的时候,如果 0≤i<L0,则 A[i] 对应 A0[i],系统就返回 h0+i×sizeof(int)作为要访问的地址,其中 h0是数组 A0的起始位置,sizeof(int) 是数组元素的大小,这里元素就是 int 型,占 4 个字节。
当用户访问越界时(即 i≥L0),系统将另外开辟一个长度为 L1的数组 A1。此时 A[i] 对应 A1[j](这里 i 和 j 之间的映射关系留给你去推导)。如果 0≤j<L1,则返回 h1+j×sizeof(int) 作为要访问的地址,其中 h1是数组 A1的起始位置。
当 A1[j] 继续越界时,系统就按照上述规则继续开辟另一个长度为 L2的数组 A2,并以此类推。
本题就请你实现这个系统功能,为用户的任何一次访问返回对应元素的地址。

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

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

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

输出格式:
对每个用户访问,在一行中输出对应的地址。但如果用户的访问超出了 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
样例说明:
访问 A[2] 即 A0[2],元素的地址就是 2048+2×4=2056。
访问 A[12],则只加开 A1不够,需要加开 A2,其初始位置 h2=4016,则 A[12]=A2[1] 的地址就是 4016+1×4=4020。
访问 A[25],则必须加开 A3,其初始位置 h3=1024,则 A[25]=A3[4] 的地址就是 1024+4×4=1040。
访问 A[50] 超出了允许创建的数组的最大边界,所以是非法访问,新数组未创建。
访问 A[28],则必须加开 A4,其初始位置 h4=3072,则 A[28]=A4[0] 的地址就是 3072。
访问 A[8]=A1[3],所以地址是 128+3×4=140。
访问 A[39]=A4[11],地址就是 3072+11×4=3116。
上述访问一共创建了 5 个数组。

#include<bits/stdc++.h>
#define ll long long
//typedef long long ll;
#define endl '\n'
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f;
struct node{
	int st,len;
}s[N];
int n,k,x,ans=1,sum;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i].st>>s[i].len;
		sum+=s[i].len;
	}
	for(int i=1;i<=k;i++)
	{
		cin>>x;
		if(x>=sum)
		{
			cout<<"Illegal Access"<<endl;
			continue;
		}
		for(int j=1;j<=n;j++)
		{
			if(x>=s[j].len)
			{
				x-=s[j].len;
				continue;
			}
			cout<<x*4+s[j].st<<endl;
			ans=max(ans,j);
			break;
		}
	}
	cout<<ans;
}

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

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

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

输出格式:
在一行中按照取帽子的顺序输出帽子主人的编号。数字间以 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+10;

map<int,int>mp1,mp2;
int a[N],b[N],c[N];
int n;

bool cmp(int a,int b)
{
    return a>b;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    cin>>n;
    
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        c[i]=a[i];
    }
    sort(a,a+n,cmp);
    
    for(int i=0;i<n;i++)
    {
        cin>>b[i];
        mp1[b[i]]=i+1;
    }
    sort(b,b+n,cmp);
    
    for(int i=0;i<n;i++)
    {
        mp2[a[i]]=b[i];
    }
    
    for(int i=n-1;i>=0;i--)
    {
        cout<<mp1[mp2[c[i]]];
        if(i!=0)
            cout<<" ";
    }
    cout<<endl;
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Null_zyd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值