一、前言

第二期模拟赛,在编程大题部分比第一期简单不少,题目数量也回归到正常的10道题。
主要知识点:进制转换、数位和、约数个数、BFS/DFS、滑动窗口。

二、题解

1. 难度⭐

问题描述

小蓝要在屏幕上放置一行文字,每个字的宽度相同。
  小蓝发现,如果每个字的宽为 36 像素,一行正好放下 30 个字,字符之间和前后都没有任何空隙。
  请问,如果每个字宽为 10 像素,字符之间不包含空隙,一行可以放下多少个字?

题解

36*30/10=108,见面送分题,下一个。

2. 难度⭐

问题描述

求 2**2023%1000,即 2的2023次方除以1000的余数。

题解

如果用pow(2,2023)去算,C++没法存储这么大的数 ,所以直接硬算方法行不通 。
但是,可以通过数学归纳法得到幂的余数计算方法,比如要算2^10 % 100,可经过如下过程得到:

1*2 %100 =2
2*2%100=4
4*2%100=8  (2^3)
...
56*2%100=12 (2^9)
12*2%100=24  (2^10)

也就是

int x=1;
for(i=1;i<=10;i++)
	x=x*2%100;

因此就用到了如下的解答方法

#include <bits/stdc++.h>
using namespace std;
int main(){
	
	int ans=1;
	for(int i=1;i<=2023;i++){
		ans=ans*2%1000; //只让余数一直乘以2就行
	}
	cout<<ans;
	return 0;
}

答案是608

3. 难度⭐

问题描述

如果一个正整数转化成二进制与转换成八进制后所有数位的数字之和相等,则称为数位和相等的数。
前几个数位和相等的正整数为 1, 8, 9, 64, ……
请问第 23 个数位和相等的正整数是多少?

题解

考察了取数位以及十进制向其他进制转换。

#include <bits/stdc++.h>
using namespace std;
//十进制转换二进制
int two(int x){
	int sum=0;
	while(x){
		sum+=x%2;
		x/=2;
	}
	return sum;
}
//十进制转换八进制
int eight(int x){
	int sum=0;
	while(x){
		sum+=x%8;
		x/=8;
	}
	return sum;
}
int main(){
	int cnt=0;
	for(int i=1;;i++){
		if(two(i)==eight(i)){
			cnt++;
			if(cnt==23){  //计数到第23个时输出并退出循环
				cout<<cnt;
				break;
			}
		}
	}
	return 0;
}

答案是4169

4. 难度⭐

问题描述

对于以下这些数(6行,每行6个,共36个),请问约数个数最多的是哪个?(如果有多个,请回答出现最早的那个)

393353 901440 123481 850930 423154 240461
373746 232926 396677 486579 744860 468782
941389 777714 992588 343292 385198 876426
483857 241899 544851 647930 772403 109929
882745 372491 877710 340000 659788 658675
296521 491295 609764 718967 842000 670302

题解

找到一个数的约数并计数,比较所有数的约数找到最大的即可

#include <bits/stdc++.h>
using namespace std;
//约数个数统计
int fun(int x){
	int cnt=0;
	for(int i=1;i<=x;i++){
		if(x%i==0) cnt++;
	}
	return cnt;
}
int main(){
	int MAX=-1,idx;
	int a[50];
	for(int i=0;i<=35;i++){
		cin>>a[i];
	}
	for(int i=0;i<=35;i++){
		int t = fun(a[i]);
		if(t>MAX){//记录约数个数最大值及其对应数组下标
			MAX = t;
			idx = i;
		}
	}
	cout<<a[idx];
	return 0;
}

答案901440

5. 难度⭐⭐⭐

问题描述

小蓝有一个01矩阵。他打算将第一行第一列的 0 变为 2 。变化过程有传染性,每次 2 的上下左右四个相邻的位置中的 0 都会变成 2 。直到最后每个 2 的周围都是 1 或 2 结束。
请问,最终矩阵中有多少个 2 ?
以下是小蓝的矩阵,共 30 行 40 列。

0000100010000001101010101001001100000011
0101111001111101110111100000101010011111
1000010000011101010110000000001011010100
0110101010110000000101100100000101001001
0000011010100000111111001101100010101001
0110000110000000110100000000010010100011
0100110010000110000000100010000101110000
0010011010100110001111001101100110100010
1111000111101000001110010001001011101101
0011110100011000000001101001101110100001
0000000101011000010011111001010011011100
0000100000011001000100101000111011101100
0010110000001000001010100011000010100011
0110110000100011011010011010001101011011
0000100100000001010000101100000000000010
0011001000001000000010011001100101000110
1110101000011000000100011001001100111010
0000100100111000001101001000001010010001
0100010010000110100001100000110111110101
1000001001100010011001111101011001110001
0000000010100101000000111100110010101101
0010110101001100000100000010000010110011
0000011101001001000111011000100111010100
0010001100100000011000101011000000010101
1001111010010110011010101110000000101110
0110011101000010100001000101001001100010
1101000000010010011001000100110010000101
1001100010100010000100000101111111111100
1001011010101100001000000011000110110000
0011000100011000010111101000101110110001

题解

这道题使用BFS,判断条件是当前位置是不是0,若是0就压入队列。
BFS请参考算法-BFS广度优先搜索

#include <bits/stdc++.h>
using namespace std;
#define N 50
typedef pair<int,int> PII;
queue<PII> q;
PII temppair;
int cnt=0;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int Map[N][N];

int check(int x, int y){
	if(x<1||x>30||y<1||y>40)
		return 0;
	if(Map[x][y]==1)
		return 0;
	if(Map[x][y]==2)
		return 0;
	return 1;
}

int bfs(int x, int y){
	q.push({x,y});
	Map[x][y]=2;
	while(!q.empty()){
		temppair = q.front();
		q.pop();
		for(int i=0;i<=3;i++){
			int nowx = dx[i]+temppair.first;
			int nowy = dy[i]+temppair.second;
			if(check(nowx,nowy)){
				q.push({nowx,nowy});
				Map[nowx][nowy]=2;
			}
		}
	}
}

int main(){
	for(int i=1;i<=30;i++){
		for(int j=1;j<=40;j++){
			scanf("%1d", &Map[i][j]);
		}
	}
	bfs(1,1);
	for(int i=1;i<=30;i++){
		for(int j=1;j<=40;j++){
			if(Map[i][j]==2) cnt++;
		}
	}
	cout<<cnt;
	return 0;
}

答案541

6. 难度⭐

问题描述

给定一个正好六位的正整数 x,请将 x 循环左移一位后输出。
所谓循环左移一位,是指将原来的十万位变为个位,原来的万位到个位向左移动依次变为十万位到十位。
  例如:194910 左移一位变为 949101 。
  又如:987123 左移一位变为 871239 。
输入格式
  输入一行包含一个整数 x 。保证输入的 x 正好包含 6 个十进制数位,而且十万位和万位上的数字均不为 0 。
输出格式
输出一行包含一个整数,表示答案。
样例输入
194910
样例输出
949101

题解

最高位(十万位)的单独取下来,被取下来之后剩下的5位数乘以10变为6位数,再加上之前的最高位即可。

#include <bits/stdc++.h>
using namespace std;
int main(){
	int x;
	cin>>x;
	x = x%100000 * 10 + x/100000;
	cout<<x;
	return 0;
}

7. 难度⭐

问题描述

输入一个仅包含小写英文字母的字符串,请问这个字符串中的最后一元音是什么。
在英文中,a,e,i,o,u 共5 个字母是元音字母,其它字母不是元音字母。
输入格式
输入一行包含一个字符串,仅由小写英文字符组成,字符串中至少包含一个元音字母
输出格式
输出一行包含一个字符,表示答案
样例输入
lanqiao
样例输出
o
样例输入
cup
样例输出
u
评测用例规模与约定
对于所有评测用例,1<= 字符数量<= 10000

题解

开一个字符数组和字符型的答案变量,遍历字符数组,只要是aeiou之中的一个就将答案变量等于它。

#include <bits/stdc++.h>
using namespace std;
char s[10002];
int main() {
	cin >> s;
	char t;
	for (int i = 0; i < strlen(s); i++) {
		if (s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u')
			t = s[i];
	}
	cout << t;
	return 0;
}

8. 难度⭐⭐

问题描述

给定一个整数,对这个整数的一次转换是指将这个整数变为这个整数的所有数位上的非零数字的乘积。
  例如,对 123456789 进行一次转换变为 123456789=362880,再进行一次转换变为 36288=2304,再进行一次转换变为 234=24,再进行一次转换变为 8。
  给定一个整数,请依次将转换过程中经历的每个整数输出,直到小于 10 。
输入格式
输入一行包含一个整数 n 。
输出格式
输出多行,每行包含一个整数。
样例输入
123456789
样例输出
362880
2304
24
8

题解

这道题要得满分一定记得开long long int ,包括函数的实参那里。

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

void fun(long long int x){
	res=1;
	while(x){
		if(x%10!=0)
			res*=x%10;
		x/=10;
	}
	//在res大于10时都默认换行,再把当前量给到fun()函数里继续输出
	if(res>10){
		cout<<res<<endl;
		fun(res);
	}
	//在res小于10时输出但不换行,以免被判错
	else
		cout<<res;
}

int main(){
	long long int n;
	cin>>n;
	fun(n);
	return 0;
}

9. 难度⭐⭐⭐

问题描述

小蓝站在一个 n 行 m 列的方格图中间,方格图的每一个方格上都标有一个正整数。
  如果两个相邻方格(上下左右四个方向相邻)内的数的最大公约数大于 1 ,则可以从其中一个方格移动到另一个方格,当然也可以从另一个方格移回第一个方格。
  假设小蓝开始时站在第 r 行第 c 列,请问小蓝可以移动到方格图内的多少个方格?
输入格式
  输入的第一行包含两个整数 n, m ,用一个空格分隔,表示方格图的行数和列数。
  接下来 n 行,每行包含 m 个正整数,相邻整数间用一个空格分隔,依次表示方格图中从第 1 行到第 n 行,每行从第 1 列到第 m 列中的数。
  接下来一行包含两个整数 r, c,用一个空格分隔,表示小蓝所在的行号和列号。
输出格式
  输出一行包含一个整数,表示答案。
样例输入
3 4
3 6 5 5
2 4 3 5
7 8 3 8
3 2
样例输出
5

题解

这道题还是用BFS,check条件为边界和已走过当前位置,以及gcd(最大公约数)>1;
小技巧:__gcd(a,b)用来计算两个数的最大公约数,比自己手动创函数用辗转相除法计算来的快。

#include <bits/stdc++.h>
using namespace std;
#define N 50
typedef pair<int, int> PII;
queue<PII> q;
PII temppair;
int cnt = 0;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
int Map[N][N];  
int done[N][N]; //记录是否走过
int n,m;
int check(int x,int y){
	if(x<1||x>n||y<1||y>m)
		return 0;
	if(done[x][y]==1)
		return 0;
	return 1;
}

void bfs() {
	while (!q.empty()) {
		temppair = q.front();
		q.pop();
		for (int i = 0; i <= 3; i++) {
			int nowx = dx[i]+temppair.first;
			int nowy = dy[i]+temppair.second;
			if (check(nowx,nowy)&& __gcd(Map[temppair.first][temppair.second],Map[nowx][nowy])>1) {
				q.push({nowx,nowy});
				cnt++;
				done[nowx][nowy]=1;
			}
		}
	}
}
int main() {
	int r, c;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++)
			cin >> Map[i][j];
	}
	cin >> r >> c;
	q.push({r, c});
	bfs();
	cout<<cnt;
	return 0;
}

10. 难度⭐⭐⭐

问题描述

给定一个序列 a[1], a[2],…, a[n] 和一个整数 k,请找出一个长度正好为 k 的区间,使得区间中所有数的和最大。
即要找到一个整数 p,使得 1<= p 且 p+k-1 <= n ,使得a[p]+a[p+1]+…+a[p+k-1] 最大。
输入格式
输入的第一行包含两个整数 n,k
第二行包含 n 个整数,相邻的整数之间使用一个空格分隔,表示给定的序列。
输出格式
输出一行包含一个整数,表示最大的区间和,你只需要输出和就行,不需要输出方案
样例输入
6 3
2 3 9 1 9 5
样例输出
19
评测用例规模与约定
对于 30%的评测用例,1 <= k <= n <= 30,1 <= a[i] <=
100
对于 60% 的评测用例,1 <= k <= n <= 1000,1 <= a[i]<= 10000.
对于所有评测用例,1 <= k <= n <= 100000,1 <= a[i]<= 1000000。

题解

不要被题干那么多字母描述吓住了,研究明白样例就行。
这道题用到滑动窗口,长度为k。
2+3+9=14
往右滑动一个
3+9+1=13
往右滑动一个
9+1+9=19(最大)
往右滑动一个
1+9+5=15
不能往右滑动了,不然就超出范围了。
所以如果看区间最左端点可取到的点,就是索引下标为[1,n-k+1]之间的整数,在样例中就是第1 2 3 4个索引。

#include <bits/stdc++.h>
using namespace std;
int a[1000002];
int main(){
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	int MAX=-1;
	for(int i=1;i<=n-k+1;i++){
		int sum=0;
		for(int j=0;j<k;j++){
			sum+=a[i+j];
		}
		MAX = max(sum,MAX);
	}
	cout<<MAX;
	return 0;
}