2023年PAT乙级秋考

119 阅读10分钟

B-1 被3整除 简单1次过

已知一个正整数能被 3 整除,要满足的条件是其各位数字之和能被 3 整除。 本题就请你判断任一给定正整数是否能被 3 整除。

输入格式: 输入第一行给出一个正整数 n(≤10),随后 n 行,每行给出一个正整数。题目保证每个整数都不超过 104 位。

输出格式: 对每个输入的整数,如果能被 3 整除,就在对应的一行中输出 Yes,否则输出 No。随后空 1 格,输出这个整数各位数字的和。

输入样例:

3
1234567890
98765432123
7257482459821364032585428796

输出样例:

  • Yes 45
  • No 50
  • No 136

思想

字符串存储

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

int solve(string x)
{
	LL  sum = 0;
	for (int i = 0; i < x.size(); i++)
	{
		sum += x[i]-'0';
	}
	return sum;
}
int main()
{
	
	int n; cin >> n;
	for (int i = 0; i < n; i++)
	{
		LL sum = 0;
		string x; cin >> x;
		sum=solve(x);
		if (sum % 3 == 0)
		{
			cout << "yes" << " " << sum << endl;
		}
		else
		{
			cout << "No" << " " << sum<<endl;
		}
	}
	return 0;
}

B-2 生日推算

有一道推理题的原文是这样的:甲、乙、丙、丁、戊的生日是在连续的五天里,先后顺序满足以下条件:

  • 甲比丙大几天,乙就比戊小几天;
  • 丁比戊大 2 天;
  • 丙的生日是在星期三。 问另外四人的生日分别在星期几?

现在我们把条件一般化,任意打乱他们的顺序,任意给定其中一人的生日,请你编写程序推算另外四人的生日分别在星期几。

注意到在上述条件描述中,只有“戊”这个人是没有任何信息直接给出的,其他人都有一个与他人关系或自己生日的描述。

输入格式:

输入分 5 行,每行给出一个人的已知信息。其中:

  • 如果是一个 [1, 7] 区间内的整数,则表示这个人的生日已知。数字 1 到 7 顺次表示星期一到星期日。

  • 如果是一个问号 ?,则表示这个人是原文中的“戊”,没有任何信息直接给出。

  • 如果是 -2,则表示这个人比 ? 对应的人大 2 天。

  • 如果是 -x,则表示这个人比那个生日已知的人大 x 天。

  • 如果是 +x,则表示这个人比 ? 对应的人小 x 天。

输出格式:

在一行中按照输入的顺序给出对应每个人的生日,数字间和行首尾都不要有空格。

输入样例:

3
?
-2
-x
+x

输出样例:

32714

注意:星期一的前一天是星期日。样例输出中,第三个人最大,是星期日过生日。

code

作者:狮子王司
链接:https://www.zhihu.com/question/292174259/answer/3218071939
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

int main()
{
    vector<string> res;
    int t=5;
    int a;
    while(t--)
    {
        string s;
        cin>>s;
        if(s[0]>='1'&&s[0]<='7') a=s[0]-'0';
        res.push_back(s);
    }

     unordered_map<string,int>h;
    if(a==1)
    {
       h["-2"]=5;
        h["-x"]=6;
        h["?"]=7;
        h["1"]=1;
        h["+x"]=2;
    }
    else if(a==2)
    {
          h["-2"]=6;
        h["-x"]=7;
        h["?"]=1;
        h["2"]=2;
        h["+x"]=3;
    }
    else if(a==3)
    {
          h["-2"]=7;
        h["-x"]=1;
        h["?"]=2;
        h["3"]=3;
        h["+x"]=4;
    }
    else if(a==4)
    {
           h["-2"]=1;
        h["-x"]=2;
        h["?"]=3;
        h["4"]=4;
        h["+x"]=5;
    }
    else if(a==5)
    {
          h["-2"]=2;
        h["-x"]=3;
        h["?"]=4;
        h["5"]=5;
        h["+x"]=6;
    }
    else if(a==6)
    {
         h["-2"]=3;
        h["-x"]=4;
        h["?"]=5;
        h["6"]=6;
        h["+x"]=7; 
    }
    else 
    {
        h["-2"]=4;
        h["-x"]=5;
        h["?"]=6;
        h["7"]=7;
        h["+x"]=1;
    }

    for(auto x:res) cout<<h[x];

  return 0;
}

B-3 计算小达人争霸赛 简单1次过

“计算小达人”争霸赛开始啦!因为参加比赛的小朋友太多了,老师们来不及人工判题,就请你写个程序来帮忙。你要根据每位小朋友的答题记录判断他/她答对了多少题,并且给出冠军的名字。

输入格式:

输入第一行给出 2 个正整数 N(≤1000)和 M(≤100),分别为参赛小朋友的人数和每人回答的问题数。接下来给出 N 个小朋友的答题记录,格式为:


小朋友姓名
A1 + B1 = C1
A2 + B2 = C2
...
AM + BM = CM

其中小朋友姓名是不含空格、仅由英文字母组成的、不超过 20 个字符的字符串。随后的 M 行,每行给出一个加法算式,算式中的每个数字都是两位数的正整数,数字和加号、等号间都有 1 个空格分隔。

输出格式:

判断每个加法算式是否正确,从而统计出每个小朋友做对了多少题。做对最多题数的是冠军。题目保证冠军只有 1 个。输出的格式为:首先按照输入的顺序,每行输出一个小朋友的姓名和他/她做对的题目数,其间以 1 个空格分隔。最后一行输出:Guan Jun Shi XXX!,这里 XXX 就是冠军的姓名。

输入样例:

4 3
XiaoHua
12 + 34 = 46
21 + 39 = 50
45 + 28 = 12
XiaoMing
22 + 33 = 55
58 + 13 = 71
67 + 30 = 97
XiaoLiang
30 + 20 = 40
18 + 19 = 35
37 + 42 = 77
XiaoHong
25 + 36 = 61
81 + 12 = 93
17 + 48 = 55

输出样例:

XiaoHua 1
XiaoMing 3
XiaoLiang 0
XiaoHong 2
Guan Jun Shi XiaoMing!

思想

模拟题,按照要求模拟即可。我这里把加法算式用字符串读入,然后提取出来两个加数与和,判断一下加数相加的和与读入的和是否一致即可。

code

#include<bits/stdc++.h>
using namespace std;
int maxcnt = -1; 
string maxname,name;
int cnt;
int main()
{
	int n, m; cin >> n >> m;
	for (int i = 0; i < n; i++)
	{
		cin >> name;
		cnt=0;
		getchar();
		for (int j = 0; j < m; j++)
		{
			string qian = "", hou = "", op = "",sum="";
			string s; getline(cin,s);
			    int k = 0;
				//提取第一个加数
				while(isdigit(s[k])&&k<s.size())
				{
					qian += s[k];
					k++;
				}
				while (!isdigit(s[k]))k++;  //跳过空格和+号

				//提取第二个加数
				while (isdigit(s[k])&&k<s.size())
				{
					hou += s[k];
					cout << "s[k]:" << s[k] << endl;
					k++;
				}
				while (!isdigit(s[k]))k++;  //跳过空格和=号
                                //提取和
				while (isdigit(s[k]) && k < s.size())
				{
					sum += s[k];
					k++;
				}
				//cout << "调试: "<<qian << " " << " " << hou <<" "<<sum << endl;
				int ans = stoi(qian) + stoi(hou);
				//cout << "ans: sum:" << ans << " " << sum << endl;
				if (ans == stoi(sum))cnt++;
		}
		cout << name << " " << cnt << endl;
		if (cnt > maxcnt)
		{
			maxcnt = cnt;
			maxname = name;
		}
	}

	cout << "Guan Jun Shi " << maxname;
	return 0;
}

方法2

作者:狮子王司
链接:https://www.zhihu.com/question/292174259/answer/3218071939
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

#include<bits/stdc++.h>
using namespace std;
 struct student
{
    string name;
    int  sum;
  
};
const int N=1010;
student e[N];

bool check(string s)
{
   
    string s1=s.substr(0,2);
    string s2=s.substr(5,2);
    string s3=s.substr(10,2);

    int a(0),b(0),c(0),t=10;
    for(int i=0;i<s1.size();i++)
    {
        a+=(s1[i]-'0')*t;
        b+=(s2[i]-'0')*t;
        c+=(s3[i]-'0')*t;
        t=1;
    }

    if(a+b==c) return true;
    else return false;
}


bool cmp(student a,student b)
{
    return a.sum>b.sum;
 }

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        e[i].sum=0;
      if(i==1)  getchar();
        getline(cin,e[i].name);
        for(int j=0;j<m;j++) 
        {
            string s;
            getline(cin,s);
            if(check(s)) e[i].sum++;
        }
        cout<<e[i].name<<" "<<e[i].sum<<endl;
    }

    sort(e+1,e+1+n,cmp);

    cout<<"Guan Jun Shi "<<e[1].name<<"!"<<endl;
     
    return 0;
}

B-4 分组数列

一个分组数列是按以下规律定义的:第 1 组包含 1 个数字,为 0×3+1;第 2 组包含 2 个数字,为 0×3+2 和 1×3+2;第 3 组包含 3 个数字,为 1×3+3, 2×3+3 和 3×3+3;以此类推。 一般来说,第 i 组包含 i 个数字,从上一组最后一个数字加 1 开始,每次增 3。例如第 3 组可以理解为:包含 3 个数字,从第 2 组最后一个数字 5 加 1(即 6)开始,增 3 得到第 2 个数字为 9,再增 3 得到第 3 个数字为 12。

所以根据定义,这个序列前 10 个数字就是:1, 2, 5, 6, 9, 12, 13, 16, 19, 22。它们实际上分成了 4 个组,即:{1}, {2, 5}, {6, 9, 12}, {13, 16, 19, 22}。 本题就请你找出任意一个给定数字是这个数列的第几项。

输入格式:

输入第一行首先给出一个正整数 n (≤105),是待查询的数字个数。随后 n 行,每行给出一个查询的正整数,所有数字都不超过 105。

输出格式:

对每个查询的正整数,输出其在数列中的序号(从 1 开始)。如果这个数字不在数列中,则输出 Not Found

输入样例:

4
12
16
5941
87654

输出样例:

6
8
2023
Not Found

思想

对于这种查询问题,我们直接提前预处理一下即可。这里把1-1e5分别对于的位置算出来
这样可以极大的节省时间 重新查询会超时。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[2 * N], tt, he;
int main()
{
	int n; cin >> n;
	int j = 1,t=1;
	

	//预处理
	while (he <= N)
	{
		he += 1;
		a[he] = j;
		j++;
		for (int i = 1; i < t; i++)
		{
			he += 3;
			a[he] = j;
			j++;
		}
		t++;  //t控制当前是第几轮
	}


	for (int i = 0; i < n; i++)
	{
		cin >> tt;
		if (a[tt] != 0)
		{
			cout << a[tt] << endl;
		}
		else
		{
			cout << "Not Found" << endl;
		}
	}
	return 0;
}

B-5 两头进一头出

某队列允许在其两端进行入队操作,但仅允许在一端进行出队操作。现给定入队的序列,请你判断一系列出队序列是否可能。例如按 1、2、3、4、5 的顺序入队,则 1、3、2、5、4 这样的出队序列是可以得到的,但 5、1、3、2、4 就是不可能得到的。

输入格式:

输入首先在一行中给出两个正整数 N 和 K(≤10),分别是入队元素的个数和待查验的序列个数。随后一行给出 N 个两两不同的整数(每个都不超过 106)组成的入队序列;再跟着 K 行,每行给出由 N 个入队整数组成的出队序列。同行整数间以空格分隔。

输出格式:

对每个需要查验的出队序列,如果是可能的,则在一行中输出 yes,否则输出 no

输入样例:

5 4
10 2 3 4 5
10 3 2 5 4
5 10 3 2 4
2 3 10 4 5
3 5 10 4 2

输出样例:

yes
no
yes
no

思想

模拟一下入队出队的过程,首先用给定的出队队列做一个哈希映射,映射一下出队队列元素的下标。然后去入队队列中找。

如果下一个要入队的元素和比当前入队队列队头的下标大,说明下一个要入队的元素出队要晚,那么就加入队尾,否则说明比当前入队队列队头出队早,将它加入到队头。

code

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 1e6 + 10;

int n, k;
int a[N], b[N],idx[N];

bool check()
{
	int res= 1;
	deque<int>q;

	for (int i = 1; i <= n; i++)
	{
		if (q.empty())q.push_back(a[i]);
		else
		{
			int t = q.front();
			if (idx[a[i]] > idx[t])q.push_back(a[i]);   //说明a[i]要比队头后出队,加入队尾
			else q.push_front(a[i]);
		}
		while (q.size() && q.front() == b[res])  //出队队列队头和入队队列队头一样,满足出队要求
			q.pop_front(), res++;
	}
	return res == n + 1;  //是否所有出队元素都从入队队列中出队
}
void solve()
{
	cin >> n >> k;
	for (int i = 1; i <= n; i++)cin >> a[i];

	while (k--)
	{
		bool flag = 1;
		for (int i = 1; i <= n; i++)
		{
			cin >> b[i];
			idx[b[i]] = i;
			if (a[i] != b[i])flag = 0;
		}
		if (flag)cout << "yes" << endl;  //a[i]=b[i],说明入队顺序本身就是一种出队顺序
		else cout << (check()?"yes":"no") << endl;
	}
}
int main()
{
	cin.tie(nullptr)->sync_with_stdio;
	int t = 1;
	while (t--)
	{
		solve();
	}

	return 0;
}