B-1 能不能整除
有无穷多正整数 n 可以整除 2n−2,我们称这样的 n 是“能整除”的数。本题就请你找出给定区间内所有能整除的数。
注:a 可以整除 b 是指 b/a 是一个整数。
输入格式:
输入在一行中给出两个正整数 a 和 b(1≤a≤b≤60),数字间以空格分隔。
输出格式:
按递增序输出闭区间 [a,b] 内“能整除”的数,每个数字占一行。但如果一个都没有,则在一行中输出 No Solution
。
输入样例 1:
15 20
输出样例 1:
17
19
输入样例 2:
8 10
输出样例 2:
No Solution
AC代码:
本题注意需要使用(long long)来确保精度问题。
#include "bits/stdc++.h"
using namespace std;
int main()
{
int a, b;
cin >> a >> b;
int flag = 1;
for(int i = a; i <= b; i++)
{
if(((long long)pow(2, i) - 2) % i == 0){
flag = 0;
cout << i << endl;
}
}
if(flag){
cout << "No Solution";
}
return 0;
}
B-2 人类的本质
本题借鉴了知乎用户的一篇文章《人类的本质就是复读机》。文中说“众所周知,人类的本质就是复读机,而且是劣质复读机。”因为“当看到大人说了‘狗’,‘猫’,‘花猫’后,你能对类似的情形使用‘花狗’,这便是劣质复读。”即“我们通过复读格式而不仅仅是内容,来处理要复读无限个对象的困难。”
本题就请你写程序模仿这个劣质复读的行为:
- 当大人说出一个字时,你只需要简单复读这个字,不需要记住任何内容;
- 当大人说出连续的多个字,而此时你脑子里没有记住任何字时,你首先简单地复读这些字,同时记住第一个字;
- 当大人说出连续的多个字,而此时你脑子里记忆了一个字时,你要把记住的那个字写在最前面,然后复读大人说出的这些字;同时把脑子里记住的字更新为当前大人说的第一个字。
看看这样做是否能让我们“表现得像个能思考的人”。
输入格式:
输入第一行首先给出一个正整数 n (≤100),是大人说出的句子数量。随后 n 行,每行给出一句话。
“一句话”由不超过 10 个“字”组成。每个“字”是仅由小写英文字母组成的、长度不超过 8 个字母的字符串。相邻两个“字”之间用 1 个空格分隔,行首位没有多余空格。每行以一个回车结束。
输出格式:
对大人给出的每个句子,按照劣质复读机的规则给出你的输出。每个句子占一行,相邻两个“字”之间用 1 个空格分隔,行首位没有多余空格。
输入样例:
6
mao
hua mao
gou
tu gou
da sha gua
da sha gua
输出样例:
mao
hua mao
gou
hua tu gou
tu da sha gua
da da sha gua
AC代码:
isSpace方法主要用来捕获空格字符(' ')的存在,然后用于分类讨论。
情况一:如果没有空格字符,说明就一个单词,直接输出即可。
情况二:如果有空格字符,说明有多个单词,此时检查vector中是否存在上一次的“记忆”,如果存在则先输出记忆,不存在则直接输出字符串;如果不存在则直接输出字符串,并把当前字符串的第一个单词保存为“记忆”。
#include "bits/stdc++.h"
using namespace std;
int isSpace(string s);
int main()
{
int n;
cin >> n;
getchar();
vector<string> v;
for(int i = 0; i < n; i++){
string speak;
getline(cin, speak);
if(!isSpace(speak)){
cout << speak << endl;
}else{
if(v.empty()){
stringstream ss;
for(int j = 0; j < speak.length(); j++){
if(speak[j] != ' '){
ss << speak[j];
}else if(speak[j] == ' '){
ss << speak[j];
break;
}
}
v.push_back(ss.str());
cout << speak << endl;
}else{
stringstream ss;
for(int j = 0; j < speak.length(); j++){
if(speak[j] != ' '){
ss << speak[j];
}else if(speak[j] == ' '){
ss << speak[j];
break;
}
}
cout << v[0];
v.erase(v.begin(), v.end());
v.push_back(ss.str());
cout << speak << endl;
}
}
}
return 0;
}
int isSpace(string s)
{
for(int i = 0; i < s.length(); i++){
if(s[i] == ' '){
return 1;
}
}
return 0;
}
B-3 开车还是地铁
杭州承办了 2022 亚运会。为缓解亚运时的交通压力,杭州市政府决定在 2023 年 9 月 18 日至 10 月 9 日期间实行特殊的限行规定,对所有浙 A 小客车实行“单双号通行”,其中“单双号通行”规则为:按机动车号牌最后一位阿拉伯数字,实行“单日单号、双日双号”通行(单号为1、3、5、7、9;双号为2、4、6、8、0)。例如 9 月 23 日,车牌为浙A 12345 的小客车允许通行,而浙A 1234Q 的小客车则不允许通行。
而在 2023 年的其他日子里,杭州实行“工作日错峰出行”的限行措施,即:按机动车号牌最后一位阿拉伯数字,周一尾号 1 和 9 禁行,周二尾号 2 和 8 禁行,周三尾号 3 和 7 禁行,周四尾号 4 和 6 禁行,周五尾号 5 和 0 禁行的规则,周六日不限行。
现在给定你若干个 5 位的机动车号牌以及对应的出行日期,请你判断该号牌在出行日期是否限行。
输入格式:
输入第一行是一个正整数 N (1≤N≤50),表示有 N 个询问。
接下来的 N 行,每行首先是两个正整数 M 和 D,表示日期为 2023 年 M 月 D 日。然后是一个 5 位的车牌号码,保证车牌号码一定至少含有一个阿拉伯数字,并且只含有大写字母和数字,且日期一定合法。
已知 2023 年 1 月 1 日是周日。为方便起见,不考虑放假等特殊情况。
输出格式:
对于每个询问,如果车牌在出行日期禁行,则输出 Yes,否则输出 No。
输入样例:
5
9 17 12345
9 18 12345
9 19 12345
2 28 2QQQQ
12 31 4A23B
输出样例:
No
Yes
No
Yes
No
AC代码:
注意:禁行输出“Yes”,否则输出“No”
首先使用getMonthDays()获取到2023年每个月多少天。然后根据2023年1月1日是周日(已知)进行推算,使用getWeekofDays()获取到周几,然后使用getlastNum()获取车牌的最后一位数字,进行相应的条件判断即可。
#include "bits/stdc++.h"
using namespace std;
int getMonthDays(int month);
int getWeekofDays(int month, int day);
int getlastNum(string id);
int main()
{
int N;
cin >> N;
for(int i = 0; i < N; i++)
{
int months, days;
string car;
cin >> months >> days >> car;
int day = getWeekofDays(months, days);
if((months == 9 && days >= 18 && days <= 30) || (months == 10 && days >= 1 && days <= 9)){
if(days % 2 == 0){
if(getlastNum(car) % 2 == 0){
cout << "No" << endl;
}else{
cout << "Yes" << endl;
}
}else{
if(getlastNum(car) % 2 != 0){
cout << "No" << endl;
}else{
cout << "Yes" << endl;
}
}
}else{
if(day == 1){
if(getlastNum(car) == 1 || getlastNum(car) == 9){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
}else if(day == 2){
if(getlastNum(car) == 2 || getlastNum(car) == 8){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
}else if(day == 3){
if(getlastNum(car) == 3 || getlastNum(car) == 7){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
}else if(day == 4){
if(getlastNum(car) == 4 || getlastNum(car) == 6){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
}else if(day == 5){
if(getlastNum(car) == 5 || getlastNum(car) == 0){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
}else{
cout << "No" << endl;
}
}
}
return 0;
}
int getMonthDays(int month)
{
switch(month){
case 1:
return 31;
case 2:
return 28;
case 3:
return 31;
case 4:
return 30;
case 5:
return 31;
case 6:
return 30;
case 7:
return 31;
case 8:
return 31;
case 9:
return 30;
case 10:
return 31;
case 11:
return 30;
case 12:
return 31;
}
}
int getWeekofDays(int month, int day)
{
int sumDay = 7;
for(int i = 1; i < month; i++){
sumDay += getMonthDays(i);
}
for(int i = 1; i < day; i++){
sumDay++;
}
return (sumDay % 7 == 0 ? 7 : (sumDay % 7));
}
int getlastNum(string id)
{
for(int i = id.length() - 1; i >= 0; i--)
{
if(id[i] >= '0' && id[i] <= '9'){
return id[i] - '0';
}
}
return -1;
}
B-4 方格填数
2014 年哈佛-麻省理工数学竞赛中一道题是这样的:将正整数 1, 2, ..., 64 填入 8×8 的方格棋盘中,使得对任何 1≤i<64,i 和 i+1 都必须填在两个具有公共边的方格中。求棋盘上对角线中所填数的和的最大值。(注意:两个对角线都要考虑;64 和1 也必须填在两个具有公共边的方格中。)
这题有点难…… 幸好我们并不要求你写程序解决这个问题。
你的任务是:对任一给定的数字填充方案,判定其是否满足填充的条件,并且在所有给出的方案中,找出满足条件的、且对角线数字和最大的那个方案。
输入格式:
输入在一行中首先给出两个正整数 n(≤100) 和 m(≤20),分别为棋盘的规模(即棋盘有 n×n 个方格)和输入的方案数量。因为容易证明奇数 n 一定不存在满足条件的解,所以题目保证给出的 n 都是偶数。
随后给出 m 个填充方案,每个方案占 n 行,每行 n 个不超过 n2 的数字。同行数字间以空格分隔。
输出格式:
在一行中首先输出满足条件的、且对角线数字和最大的方案数。随后一行中按照递增序输出这些方案的编号(编号按输入的顺序从 1 到 m)。
注意每行数字间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
4 5
16 1 2 3
15 14 13 4
10 11 12 5
9 8 7 6
16 1 2 3
15 14 13 4
10 11 12 5
9 8 7 10
15 16 1 2
14 13 4 3
11 12 5 6
10 9 8 7
3 4 5 6
2 13 12 7
1 14 11 8
16 15 10 9
10 5 4 3
7 12 13 2
8 11 14 1
9 6 15 16
输出样例:
2
1 4
AC代码:
judge()函数模拟判断 i 和 i+1的关系(不要忘记最后n^2和1的那一次)。sumValue()函数计算对角线的值,将所有模拟通过的值放入一个map集合中,键为index序列号,值为对角线的值,并在放的过程中捕捉最大对角线的值,而后使用迭代器遍历map,输出满足最大值的序列号即可。
注意:当没有条件满足即 cnt = 0 时,而后一行的输出还要存在,即最后要写成(cout << res << endl;)√ ,不能写成(cout << res)要不然会出现测试点2格式错误。
#include "bits/stdc++.h"
using namespace std;
map<int, int> mp;
int judge(int n, int matrix[150][150]);
int sumValue(int n, int matrix[150][150]);
int main()
{
int n, m;
cin >> n >> m;
int maxValue = 0;
for(int i = 0; i < m; i++)
{
int matrix[150][150];
for(int j = 0; j < n; j++){
for(int k = 0; k < n; k++){
cin >> matrix[j][k];
}
}
if(judge(n, matrix)){
int value = sumValue(n, matrix);
if(value > maxValue){
maxValue = value;
}
mp[i + 1] = value;
}
}
int cnt = 0;
int flag = 0;
stringstream ss;
for(map<int, int>::iterator it = mp.begin(); it != mp.end(); it++)
{
if(it->second == maxValue){
if(cnt){
ss << " ";
}
ss << it->first;
cnt++;
}
}
cout << cnt << endl;
string res = ss.str();
cout << res << endl;
return 0;
}
int judge(int n, int matrix[150][150])
{
int x, y;
int flag = 1;
for(int i = 0; i < n && flag; i++)
{
for(int j = 0; j < n && flag; j++)
{
if(matrix[i][j] == 1){
x = i;
y = j;
flag = 0;
}
}
}
if(flag){
return 0;
}
int cnt = 2;
while(cnt <= n * n){
int able = 0;
if(x - 1 >= 0 && matrix[x - 1][y] == cnt){
able = 1;
x = x - 1;
cnt++;
}else if(x + 1 < n && matrix[x + 1][y] == cnt){
able = 1;
x = x + 1;
cnt++;
}else if(y - 1 >= 0 && matrix[x][y - 1] == cnt){
able = 1;
y = y - 1;
cnt++;
}else if(y + 1 < n && matrix[x][y + 1] == cnt){
able = 1;
y = y + 1;
cnt++;
}
if(!able){
return 0;
}
}
if((x - 1 >= 0 && matrix[x - 1][y] == 1) || (x + 1 < n && matrix[x + 1][y] == 1) || (y - 1 >= 0 && matrix[x][y - 1] == 1) || (y + 1 < n && matrix[x][y + 1] == 1)){
return 1;
}else{
return 0;
}
}
int sumValue(int n, int matrix[150][150])
{
int sum = 0;
for(int i = 0; i < n; i++){
sum += matrix[i][i];
}
for(int i = n - 1; i >= 0; i--){
sum += matrix[(n - 1) - i][i];
}
return sum;
}
B-5 堆栈中的最大值
堆栈是一种后进先出的线性结构。本题要求你在实现普通堆栈的进栈(Push)和出栈(Pop)功能时,外加一个查看最大值(PeekMax)的功能。重点是,这个额外的功能不能影响整个堆栈的操作效率。
输入格式:
输入第一行首先给出一个正整数 n (≤105),是堆栈操作的数量。随后 n 行,每行给出一个操作,格式为:
Push X
表示将值为X
的元素入栈,其中X
是绝对值不超过 230 的整数;Pop
表示将栈顶元素出栈;PeekMax
表示要求返回此刻堆栈中最大元素的值。
输出格式:
对输入中的每个操作,按照要求执行操作。对每个 Pop
,在一行中输出出栈的元素值;对每个 PeekMax
,在一行中输出此刻堆栈中最大元素的值。若执行 Pop
或 PeekMax
时堆栈是空的,则对应输出 ERROR
,并且不执行该操作。
题目保证至少有一行输出。
输入样例:
11
Pop
Push 34
Push 28
PeekMax
Push 84
PeekMax
Pop
PeekMax
Pop
Pop
PeekMax
输出样例:
ERROR
34
84
84
34
28
34
ERROR
AC代码:
核心思想:使用map集合的“键”记录当前的最大值,“值”记录当前最大值存在于堆栈的次数,当次数为0时使用erase方法删除,否则对应次数自减1即可。
亲测有效,不会超时!
#include "bits/stdc++.h"
using namespace std;
stack<long long> st;
map<long long, int> mp;
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
string s;
cin >> s;
if(s == "Push"){
long long num;
cin >> num;
st.push(num);
if(mp.find(num) == mp.end()){
mp[num] = 1;
}else{
mp[num]++;
}
}else if(s == "Pop"){
if(st.empty()){
cout << "ERROR" << endl;
}else{
cout << st.top() << endl;
if(mp[st.top()] - 1 == 0){
mp.erase(st.top());
}else{
mp[st.top()]--;
}
st.pop();
}
}else if(s == "PeekMax"){
if(st.empty()){
cout << "ERROR" << endl;
}else{
map<long long, int>::reverse_iterator rit = mp.rbegin();
cout << rit->first << endl;
}
}
}
return 0;
}