2021PAT秋季乙级 题解和总结(附满分代码)

7-1 好数 (15 分)

在这里插入图片描述输入样例

3
1
91
50

输出样例

No 7
1 2
Yes
1 9
5 6
No 52
2 6
C++
#include<cstring>
#include<iostream>
using namespace std;
int main()
{
    int hao[10050];
    memset(hao,0,sizeof hao);
    for(int i=1;i<=100;i++)
    {
        for(int j=i+1;j<=100;j++)
        {
            int t=i*i+i*j+j*j;
            if(t<=10050)
            hao[t]=1;
        }
    }
    int n,t;
    cin>>n;
    for(int f=1;f<=n;f++)
    {
        cin>>t;
        if(hao[t]==0)
        {
            while(hao[t]==0)
            {
                t++;
            }
            printf("No %d\n",t);
            goto loop;
        }
        else
        {
            printf("Yes\n");
            loop:
            for(int i=1;i<=100;i++)
            {
                for(int j=i+1;j<=100;j++)
                {
                    int m=i*i+i*j+j*j;
                    if(m==t)
                        printf("%d %d\n",i,j);
                }
            }
        }
    }
}

在这里插入图片描述

7-2 数以类聚 (20 分)

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

输入在第一行给出一个正整数 N(≤105),第二行给出 N 个不超过 107 的正整数,数字间以空格分隔。
输出格式:
在一行中输出 N 个给定的整数可以归类的数量、以及规模最大的类中最小的乘积。数字间以一个空格分隔。

输入样例

10
1234 98 329 9552 47621 8862 5539 2333 5365 463

输出样例

7 54
C++
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
map<int,int>wz;
struct node
{
    int num;
    int a;
}t[1000050];
bool cmp(node a,node b)
{
    if(a.num==b.num)
    {
        return a.a<b.a;
    }
    return a.num>b.num;
}
int main()
{
    int n,cnt=0;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int s,sum=1;
        cin>>s;
        while(s)
        {
            sum=sum*(s%10);
            s/=10;
        }
        if(wz[sum])
        {
            t[wz[sum]].num++;
        }
        else
        {
            t[++cnt].num=1;
            t[cnt].a=sum;
            wz[sum]=cnt;
        }
    }
    sort(t+1,t+cnt+1,cmp);
    printf("%d %d",cnt,t[1].a);
}

在这里插入图片描述

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
某dalao的AC代码
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int main()
{
	int t, k[11000];
	string a, b, s;
	int maxx = 9999999;
	getline(cin, a);
	getline(cin, b);
	cin >> t;
	for (int kk = 0; kk < t; kk++)
	{
		int n, j = 0, f = 0, cnt = 0;
		cin >> n;
		string c;
		getchar();
		getline(cin, s);
		for (int i = 0; i < s.size(); i++)
		{
			if (s[i] == '0')
			{
				c += a[j];
				j++;
			}
			else if (s[i] == '1')
			{
				j++;
				cnt++;
			}
			else if (s[i] == '2')
			{
				c += '^';
				j++;
				cnt++;
			}
			else if (s[i] == '3')
			{
				c += '^';
				cnt++;
			}
			else
			{
				f = 1;
			}
		}

		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;
		}

		if (f == 0)
		{
			k[kk] = n;
			if (n < maxx) maxx = n;
		}
		else
		{
			k[kk] = -1;
		}
	}

	for (int i = 0; i < t; i++)
	{
		if (k[i] == maxx) cout << "AC" << endl;
		else cout << "WA" << endl;
	}

	system("pause");
	return 0;
}

mine:
这题最终也没把题搞明白,细节也特别多,看榜上的大佬也是一分一分上去的,只拿到了12分

C++ 12分代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
    string a,b,c,bb="  ",aa="  ";
    int n,k;
    int lea,leb;//a的原始长度  b的原始长度
    getline(cin,a);
    getline(cin,b);
    lea=a.size();
    leb=b.size();
    a+=aa;
    b+=bb;
    cin>>n;
    for(int f=1;f<=n;f++)
    {
        bool pd=1;
        int cnt=0,cn1=0,cn2=0;//cnt判断出现123的个数 cn1 a串的进度 cn2 b串的进度
        cin>>k;
        getchar();
        getline(cin,c);
        int s3=0,s1=0;
        for(int i=0;i<c.size();i++)
        {
            if(c[i]=='0') //0
            {
                if(s3>s1)
                {
                    cn2+=(s3-s1);
                    s3=s1=0;
                }
                else if(s3<s1)
                {
                    
                    cn1+=(s1-s3);
                    s3=s1=0;
                }
                if(a[cn1]==b[cn2])
                {
                    cn1++;
                    cn2++;
                }
                else
                {
                    printf("WA\n");
                    pd=0;
                    break;
                }
            }
            else if(c[i]=='1')
            {
                s1++;
                //cn1++;
                cnt++;
            }
            else if(c[i]=='2')
            {
                if(s3>s1)
                {
                    cn2+=(s3-s1);
                    s3=s1=0;
                }
                else if(s3<s1)
                {
                    cn1+=(s1-s3);
                    s3=s1=0;
                }
                cn1++;
                cn2++;
                cnt++;
            }
            else if(c[i]=='3')
            {
                s3++;
                cnt++;
                //cn2++;
            }
            else
            {
                printf("WA\n");
                pd=0;
                break;
            }
            if(cnt>k||cn1>lea||cn2>leb)
            {
                printf("WA\n");
                pd=0;
                break;
            }
        }
        if(pd)
        {
            if(a[cn1+1]!=b[cn2+1]||a[cn1+2]!=b[cn2+2])
            {
                printf("WA\n");
            }
            else printf("AC\n");
        }
    }
}

在这里插入图片描述

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

在这里插入图片描述输入样例

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 个数组。

C++
#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
struct node
{
    int add;
    int size;
}t[100050];
vector<int>wz(10050000);
//map<int,int>wz;
signed main()
{
    int n,k,all=0;
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&t[i].add);
        scanf("%d",&t[i].size);
        all+=t[i].size;
        wz[i]=all-1;
    }
    all--;
    wz[0]=-1;
    int m,use=0,ans=0,ma=1;
    for(int i=1;i<=k;i++)
    {
        scanf("%d",&m);
        if(m>all)
        {
            printf("Illegal Access\n");
            continue;
        }
        int w;
        for(int i=1;i<=n;i++)
        {
            if(m<=wz[i])
            {
                w=i;
                break;
            }
        }
        ma=max(ma,w);
        printf("%d\n",t[w].add+(m-wz[w-1]-1)*4);
    }
    printf("%d",ma);
}

在这里插入图片描述

7-5 取帽子 (25 分)

在这里插入图片描述输入样例

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 个人下一个走。

以此类推。

C++
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
struct node
{
    int num;
    int a;
}t[10050];
map<int,int>s;
//int s[10050];
struct mao
{
    int size;
    int num;
    int weici;
}ma[10050];
mao use[10050];
bool cmp1(mao a,mao b)
{
    return a.size>b.size;
}
bool cmp2(node a,node b)
{
    return a.num>b.num;
}
int main()
{
    int n,m[10050];
    cin>>n;
    for(int i=n;i>0;i--)
    {
        cin>>ma[i].size;
        ma[i].num=i;
        use[i].size=ma[i].size;
        use[i].num=i;
    }
    sort(use+1,use+1+n,cmp1);
    for(int i=1;i<=n;i++)
    {
        s[use[i].size]=i;
    }
    for(int i=1;i<=n;i++)
    {
        cin>>t[i].num;
        t[i].a=i;
    }
    sort(t+1,t+n+1,cmp2);
    for(int i=1;i<=n;i++)
    {
        int cn=ma[i].size;
        cn=s[cn];
        cn=t[cn].a;
        printf("%d",cn);
        if(i!=n) printf(" ");
    }
}

在这里插入图片描述

总结

这次乙级挺遗憾的,计划都是冲着满分去的,但是卡在了第三题上,看榜上的大佬们也是一分一分上去的,这题也真的是感觉题也没搞明白。
以后乙级应该会成为遗憾了吧,要去准备甲级了。不过也幸好达到了90分以上,拿到了十几名,只卡在了一道题上。还是自己水平太低了!

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值