2022第十三届蓝桥杯省赛C++B组 题解

试题 A: 九进制转十进制

本题总分:5分
九进制正整数(2022)9转换成十进制等于多少?
【分析】
按权展开,相加求和即可。
$$

解:(2022)9=29^ 3+29^ 1+2*9^0
$$

试题B:顺子日期

​ 本题总分:5分
【问题描述】
​ 小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456等。顺子日期指的就是在日期的yyyymmdd表示法中,存在任意连续的三位数是一个顺子的日期。例如20220123就是一个顺子日期,因为它出现了一个顺子:123;而20221023则不是一个顺子日期,它一个顺子也没有。小明想知道在整个2022年份中,一共有多少个顺子日期。
【答案提交】
​ 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

【答案解析】
​ 题目说的顺子是:连续的三个数字,并不是三位数。所以 012 也算是顺子。(逆序不算顺子)
​ 直接枚举,答案:14

20220123
.......
20220129
20221012
......
20221231

试题C:刷题统计

时间限制:1.0s 内存限制:256.0MB 本题总分:10分
【问题描述】
小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做a道题目,周六和周日每天做b道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于n题?
【输入格式】
输入一行包含三个整数a,b和n.
【输出格式】
输出一个整数代表天数。
【评测用例规模与约定】
对于50%的评测用例,1≤a,b,n≤10^6
对于100%的评测用例,1≤a,b,n≤10^18.-----long long
【问题解析】
7天做5a+2b道题,算n中有几个5a+2b,再算还需要几天

#include<iostream>
using namespace std;
int main(){
	long long a,b,n;
	cin>>a>>b>>n;
	int day=0;
	day+=(n/(5*a+2*b))*7;
	int d=n%(5*a+2*b);
	int d1=0;
    for(int i=1;i<=5;i++){
        d1+=a;
        if(d1>=d){
			cout<<day+i;
			return 0;
		}
    }
	for(int i=6;i<=7;i++){
        d1+=b;
        if(d1>=d){
            cout<<day+i;
            return 0;
        }
    }
}

试题D:修剪灌木

时间限制:1.0s 内存限制:256.0MB 本题总分:10分
【问题描述】 爱丽丝要完成一项修剪灌木的工作。有N棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晚会修剪一棵灌木,让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始, 每天向右修剪一棵灌木。当修剪了最右侧的灌木后,她会调转方向,下一天开始向左修剪灌木。直到修剪了最左的灌木后再次调转方向。然后如此循环往复。灌木每天从早上到傍晚会长高 1 厘米,而其余时间不会长高。在第一天的早晨,所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。

【输入格式】 一个正整数 N ,含义如题面所述。
【输出格式】 输出 N 行,每行一个整数,第i行表示从左到右第 i 棵树最高能长到多高。
【样例输入】 3
【样例输出】 4 2 4
【评测用例规模与约定】 对于 30% 的数据,N ≤ 10. 对于 100% 的数据,1 < N ≤ 10000.
【问题解析】
​ 首先用暴力找规律,然后再根据规律简化代码
// 暴力代码:来回走两次。注意回的时候要把两个边界去掉。


#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 1e4 + 100;
int a[maxn];
int maxHeight[maxn];
int main() {
	int n;
	while (cin >> n) {
		memset(a, 0, sizeof(a));
		memset(maxHeight, 0, sizeof(maxHeight));

		// 来回走两次
		for (int today = 0; today < n; today++) {
			for (int i = 0; i < n; i++) {
				a[i]++;
				if (a[i] > maxHeight[i]) {
					maxHeight[i] = a[i];
				}
				if (i == today) {
					a[i] = 0;
				}
			}
		}
		for (int today = n - 2; today > 0; today--) {
			for (int i = 0; i < n; i++) {
				a[i]++;
				if (a[i] > maxHeight[i]) {
					maxHeight[i] = a[i];
				}
				if (i == today) {
					a[i] = 0;
				}
			}
		}
		for (int today = 0; today < n; today++) {
			for (int i = 0; i < n; i++) {
				a[i]++;
				if (a[i] > maxHeight[i]) {
					maxHeight[i] = a[i];
				}
				if (i == today) {
					a[i] = 0;
				}
			}
		}
		for (int today = n - 2; today > 0; today--) {
			for (int i = 0; i < n; i++) {
				a[i]++;
				if (a[i] > maxHeight[i]) {
					maxHeight[i] = a[i];
				}
				if (i == today) {
					a[i] = 0;
				}
			}
		}
		for (int i = 0; i < n; i++) {
			cout << maxHeight[i] << " ";
		}
		cout << endl << endl;
	}
	return 0;
}

结果如下:

5 6 7 8 9  ---输入
8 6 4 6 8   ----4 3 2 3 4  *2

10 8 6 6 8 10 ----5 4 3 3 4 5  *2

12 10 8 6 8 10 12

14 12 10 8 8 10 12 14

16 14 12 10 8 10 12 14 16   ---8 7 6 5 4 5 6 7 8  *2

通过找规律可以简化代码:

#include <iostream>
using namespace std;

const int maxn = 1e4 + 10;
int ans[maxn];

int main() {
	int n,j;
	cin >> n;
    int curI=1;//数组当前下标
    for(j=n-1;j>=n/2;j--)ans[curI++]=j*2;
	if(!(n&1))ans[curI]=ans[curI-1],curI++;//偶数特判
    for(int i=j+2;i<=n;i++)ans[curI++]=i*2;

	for (int i = 1; i <= n; i++) {
		cout << ans[i] <<" ";
	}
	return 0;
}

试题E:X进制减法-模拟、贪心

时间限制:1.0s
内存限制:256.0MB
本题总分:15分

【问题描述】
​ 进制规定了数字在数位上逢几进一。
​ X进制是一种很神奇的进制,因为其每一数位的进制并不固定!例如说某种进制数,最低数位为二进制,第二数位为十进制,第三数位为八进制,则X进制数321转换为十进制数为65。现在有两个X进制表示的整数A和B,但是其具体每一数位的进制还不确定,只知道A和B是同一进制规则,且每一数位最高为N进制,最低为二进制。请你算出A-B的结果最小可能是多少。请注意,你需要保证A和B在X进制下都是合法的,即每一数位上的数字要小于其进制。
【输入格式】
​ 第一行一个正整数,含义如题面所述。
​ 第二行一个正整数Ma,表示X进制数A的位数。
​ 第三行M。个用空格分开的整数,表示X进制数A按从高位到低位顺序各个数位上的数字在十进制下的表示。
​ 第四行一个正整数M,表示X进制数B的位数。
​ 第五行Mb个用空格分开的整数,表示X进制数B按从高位到低位顺序各个数位上的数字在十进制下的表示。
​ 请注意,输入中的所有数字都是十进制的。
【输出格式】
​ 输出一行一个整数,表示X进制数A-B的结果的最小可能值转换为十进制后再模1000000007的结果。
【样例输入】

11
3
10 4 0
3
1 2 0

【样例输出】

94
【样例说明】

​ 当进制为:最低位2进制,第二数位5进制,第三数位11进制时,减法得到的差最小。此时A在十进制下是108,B在十进制下是14,差值是94。

【评测用例规模与约定】

​ 对于30%的数据,N≤10;Ma,Mb≤8.

​ 对于100%的数据,2≤N≤1000;1≤M,M,≤100000;A≥B.

【问题分析】

只看第1位时:
321 − > 3 ∗ 2 + 2 ∗ 2 + 1 ∗ 2 0 321 -> 3*2+2*2+1*2^0 321>32+22+120
看第2位时
321 − > 3 ∗ 2 ∗ 10 + 2 ∗ 2 + 1 321 -> 3*2*10+2*2+1 321>3210+22+1
看第3位时
321 − > 3 ∗ 2 ∗ 10 + 2 ∗ 2 + 1 321 -> 3*2*10+2*2+1 321>3210+22+1

然后这题用贪心

#include<iostream>
using namespace std;
int n;
int ma,mb;
int a[100000],b[100000],c[100000];
int jin[100000];
int main(){
	cin>>n;
	cin>>ma;
	for(int i=ma;i>=1;i--)	cin>>a[i];
	cin>>mb;
	for(int i=mb;i>=1;i--)  cin>>b[i];
	jin[0]=1;
	for(int i=1;i<=max(ma,mb);i++){
		c[i]=a[i]-b[i];
		if(c[i]>=0){
		   if(a[i]<=2&&b[i]<=2)   	jin[i]=2;
		   else		   	jin[i]=max(a[i],b[i])+1;
		}
		else{
			jin[i]=n;
		}
	}
 	
	int sum=0;
	for(int i=1;i<=max(ma,mb);i++){
		int s=1;
		for(int k=0;k<i;k++){
			s*=jin[k];
		}
		sum+=c[i]*s;
	}
	cout<<sum%1000000007;
	return 0;
}

试题F:统计子矩阵-二维前缀和(模板题)

​ 时间限制:1.0s 内存限制:256.0MB 本题总分:15分
【问题描述】
​ 给定一个NxM的矩阵A,请你统计有多少个子矩阵(最小1x1,最大NxM)满足子矩阵中所有数的和不超过给定的整数K?
【输入格式】
​ 第一行包含三个整数N,M和K.之后N行每行包含M个整数,代表矩阵A.
【输出格式】
​ 一个整数代表答案。
【样例输入】

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

【样例输出】

19

【样例说明】
​ 满足条件的子矩阵一共有19,包含:
​ 大小为1×1的有10个。
​ 大小为1×2的有3个。
【评测用例规模与约定】
​ 对于30%的数据,N,M≤20.
​ 对于70%的数据,N,M≤100.
​ 对于100%的数据,1≤N,M≤500;0≤A≤1000;1≤K≤250000000.
【注意】
k 已经超了 int 范围 ,int 范围是 -21 4748 3648 ~ 21 4748 3647 (21*10^8)
方法:使用前缀和即可。
解法1:暴力法

#include <iostream>
using namespace std;

int mat[550][550];

int main() {
	int n, m;
	long long k;
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> mat[i][j];
		}
	}
	long long sum = 0;
	long long cnt = 0;
	for (int h1 = 1; h1 <= n; h1++) {
		for (int h2 = h1; h2 <= n; h2++) {
			for (int l1 = 1; l1 <= m; l1++) {
				for (int l2 = l1; l2 <= m; l2++) {
					sum = 0;
					for (int h = h1; h <= h2; h++) {
						for (int l = l1; l <= l2; l++) {
							sum += mat[h][l];
						}
					}
					if (sum <= k) {
						cnt++;
					}
				}
			}
		}
	}
	cout << cnt << endl;
	return 0;
}

解法2:前缀和

#include <iostream>
using namespace std;

int mat[550][550];

int main() {
	int n, m;
	long long k;
	cin >> n >> m >> k;
	int data;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> data;
			mat[i][j] = mat[i - 1][j] + mat[i][j - 1] - mat[i - 1][j - 1] + data;
		}
	}
	int cnt = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			for (int x = i; x <= n; x++)
				for (int y = j; y <= m; y++) {
					int he = mat[x][y] - mat[i - 1][y] - mat[x][j - 1] + mat[i - 1][j - 1];
					if (he <= k) //求子矩阵和
						cnt++;
				}
		}
	}
	cout << cnt << endl;
	return 0;
}

试题G:积木画-2*2瓷砖拼接变形(斐波那契)

时间限制:1.0s
内存限制:256.0MB
本题总分:20分
【问题描述】
​ 小明最近迷上了积木画,有这么两种类型的积木,分别为1型(大小为2个单位面积)和L型(大小为3个单位面积):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QHKZ7lGG-1675517456754)(./FILES/2022第十三届蓝桥杯省赛C++B组个人题解.md/img-20221101213003.png)]
​ 同时,小明有一块面积大小为2×N的画布,画布由2×N个1x1区域构成。小明需要用以上两种积木将画布拼满,他想知道总共有多少种不同的方式?
积木可以任意旋转,且画布的方向固定。
【输入格式】
​ 输入一个整数N,表示画布大小。
【输出格式】
​ 输出一个整数表示答案。由于答案可能很大,所以输出其对1000000007取模后的值
【样例输入】

3

【样例输出】

5

【样例说明】
​ 五种情况如下图所示,颜色只是为了标识不同的积木:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d55hEKzR-1675517456757)(./FILES/2022第十三届蓝桥杯省赛C++B组个人题解.md/img-20221101213046.png)]
【评测用例规模与约定】
​ 对于所有测试用例,1≤N≤10000000.
【问题分析】

​ 此题时斐波那契数列的进阶应用,类似于贴瓷砖的问题,只是这个问题更复杂。
​ 这道题的规律是,第 n 列可以通过前面的排列,再加上那几种基础的排列得到。
​ 第一种情况:
​ dp[n] 可以通过 dp[n - 1] 加上普通的一列得到
​ 第二种情况:
​ dp[n] 可以通过 dp[n - 2] 加上两块横的得到
​ 第三种情况:
​ dp[n] 可以通过 dp[n - 3] 加上两个三角形的堆起来得到,但要注意的是,这两个三角形的堆叠方式有两种,所以要加上两倍的 dp[n - 3]
​ 第四种情况:
​ dp[n]可以通过 dp[n - 4] 加上由左右两个各一个三角形,中间若干个横块的组合得到,同第三种情况,这个组合可以倒过来,即有两种堆叠方式,因此要加上两倍的 dp[n - 4]

综上结论为:dp[n] = dp[n - 1] + dp[n - 2] + dp[n - 3] * 2 + dp[n - 4] * 2

初始值:

	dp[0] = 1;
	dp[1] = 1;
	dp[2] = 2;
	dp[3] = 5;
#include <iostream>
using namespace std;

const long long MOD = 1e9 + 7;

const int maxn = 1e7 + 100;
long long dp[maxn];

int main() {
	int n;
	cin >> n;
	dp[0] = 1;
	dp[1] = 1;
	dp[2] = 2;
	dp[3] = 5;
	for (int i = 4; i <= n; i++) {
		// 注意每次相加后都要取余
		dp[i] = (((((dp[i - 1] + dp[i - 2]) % MOD) + dp[i - 3] * 2) % MOD) + dp[i - 4] * 2) % MOD;
	}
	cout << dp[n] << endl;
	return 0;
}

试题H:扫雷-难-广搜

​ 时间限制:1.0s
​ 内存限制:256.0MB 本题总分:20分
【问题描述】
​ 小明最近迷上了一款名为《扫雷》的游戏。其中有一个关卡的任务如下,在一个二维平面上放置着n个炸雷,第i个炸雷(xi,yi,ri)表示在坐标(xi,y)处存在一个炸雷,它的爆炸范围是以半径为的一个圆。为了顺利通过这片土地,需要玩家进行排雷。玩家可以发射m个排雷火箭,小明已经规划好了每个排雷火箭的发射方向,第j个排雷火箭(xj,yj,rj)表示这个排雷火箭将会在(x,y)处爆炸,它的爆炸范围是以半径为r的一个圆,在其爆炸范围内的炸雷会被引爆。同时,当炸雷被引爆时,在其爆炸范围内的炸雷也会被引爆。现在小明想知道他这次共引爆了几颗炸雷?你可以把炸雷和排雷火箭都视为平面上的一个点。一个点处可以存在多个炸雷和排雷火箭。当炸雷位于爆炸范围的边界上时也会被引爆。
【输入格式】
​ 输入的第一行包含两个整数n、m.接下来的n行,每行三个整数xi,yi,ri,表示一个炸雷的信息。再接下来的m行,每行三个整数xj,yj,rj,表示一个排雷火箭的信息。

【输出格式】
​ 输出一个整数表示答案。
【样例输入】

2 1
2 2 4
4 4 2
0 0 5

【样例输出】

2

【样例输出】

2

【样例说明】
​ 示例图如下,排雷火箭1覆盖了炸雷1,所以炸雷1初盖了炸雷2,所以炸雷2也被排除。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xOOK84NV-1675517456757)(./FILES/2022第十三届蓝桥杯省赛C++B组个人题解.md/img-20221101213114.png)]
【评测用例规模与约定】
​ 对于40%的评测用例:0≤x,y≤10^9,0≤n,m≤10^3,1≤r≤10.
​ 对于100%的评测用例:0≤x,y≤10^9,0≤n,m≤5×10^4,1≤r≤10.
​ [陷阱]:一个点处可以存在多个炸雷和排雷火箭。当炸雷位于爆炸范围的边界上时也会被引爆。

没有分析

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

const int maxn = 50100;
// 记录坐标和半径
int x_pos[maxn];
int y_pos[maxn];
int radius[maxn];
bool vis[maxn]; // 用来记录这个点爆炸了没有

// 用于 bfs 的 struct,更方便处理
struct point {
	int x, y, r;
	// 将结构体放入 map 中,需要自己写一个 operator 来排序,因为 map 本身是有序的
	bool operator < (const point& p) const {
		if (x == p.x) {
			if (y == p.y) {
				return r < p.y;
			}
			return y < p.y;
		}
		return x < p.x;
	}
};

map<point, int> all;

double getDis(int x1, int y1, int x2, int y2) {
	return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

int bfs(point begin, int n) {
	int cnt = 0;
	queue<point> q;
	q.push(begin);
	while (!q.empty()) {
		point cur = q.front();
		q.pop();
		// 遍历以 2 倍半径为边长的正方形,找到其爆炸所涉及到的炸雷
		for (int i = cur.y - cur.r; i <= cur.y + cur.r; i++) {
			for (int j = cur.x - cur.r; j <= cur.x + cur.r; j++) {
				if(getDis(j, i, cur.x, cur.y) > cur.r) {
					continue;
				}
				point temp;
				temp.y = i, temp.x = j;
				for (int k = 0; k < n; k++) {
					if (!vis[k] && x_pos[k] == temp.x && y_pos[k] == temp.y) {
						temp.r = radius[k];
						q.push(temp);
						cnt++;
						all[temp]--;
						vis[k] = true; // 标记为以爆炸
					}
				}
			}
		}
	}
	return cnt;
}

int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		cin >> x_pos[i] >> y_pos[i] >> radius[i];
		vis[i] = false; // 初始化都还没有爆炸
	}
	int x, y, r;
	for (int i = 0; i < m; i++) {
		point p;
		cin >> p.x >> p.y >> p.r;
		cout << bfs(p, n) << '\n'; // dev调试还不能用endl,否则就不能进入下一步
	}
	return 0;
}

试题I:李白打酒加强版-深搜(难)或者动规

​ 时间限制:1.0s 内存限制:256.0MB 本题总分:25分
【问题描述】
​ 话说大诗人李白,一生好饮。幸好他从不开车。一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
​ 无事街上走,提壶去打酒。
​ 逢店加一倍,遇花喝一斗。
​ 这一路上,他一共遇到店N次,遇到花M次。已知最后一次遇到的是花,他正好把酒喝光了。请你计算李白这一路遇到店和花的顺序,有多少种不同的可能?
注意:壶里没酒(0斗)时遇店是合法的,加倍后还是没酒;但是没酒时遇花是不合法的。
【输入格式】
​ 第一行包含两个整数N和M.
【输出格式】
​ 输出一个整数表示答案。由于答案可能很大,输出模1000000007的结墨
【样例输入】

5 10

【样例输出】

14

【样例说明】
​ 如果我们用0代表遇到花,1代表遇到店,14种顺序如下:

010101101000000
010110010010000
011000110010000
100010110010000
011001000110000
100011000110000
100100010110000
010110100000100
011001001000100
100011001000100
100100011000100
011010000010100
100100100010100
101000001010100

【评测用例规模与约定】
​ 对于40%的评测用例:1≤N,M≤10。
​ 对于100%的评测用例:1≤N,M≤100。

​ 主要错误如下:
​ ① 一共必须要且仅要经过 N 次店,M 次花
​ ② 最后一次遇到的必须是花
​ ③ 最后遇到花后,酒必须喝光
​ ④ 在中途遇到花时,酒不能为空

#include <iostream>
#include <string>
#include <vector>
using namespace std;

const int MOD = 1e9 + 7;

void backTrack(vector<char>& temp, vector<vector<char> >& ans, int n, int m, int nn, int mm, int jiu) {
	if (jiu < 0) return; // 如果遇到花却没酒了,则不符合条件
	if (nn > n || mm > m) return; // 如果经过了多于 N 次店、M 次花,则不符合条件
	if (temp.size() == n + m) {
		if (jiu == 0 && temp.back() == '0') { // 如果最后到达的是店也不符合条件
			ans.push_back(temp);
		}
		return;
	}
	temp.push_back('0');
	backTrack(temp, ans, n, m, nn, mm + 1, jiu - 1);
	temp.pop_back();
	temp.push_back('1');
	backTrack(temp, ans, n, m, nn + 1, mm, jiu * 2);
	temp.pop_back();
}

int main() {
	int n, m;
	cin >> n >> m;
	int jiu = 2;
	vector<char> temp;
	vector<vector<char> > ans;
	backTrack(temp, ans, n, m, 0, 0, jiu);
	cout << ans.size() % MOD << endl;
	return 0;
}

分析一下。。。。。。。。。

#include<iostream>
#include<cstring>
using namespace std;
int N, M;
int dp[1000][101][101];
int dfs(int sum, int n, int m) {
    if (sum < 0)return 0;
	if (n > N)return 0;
	if (m > M - 1)return 0;
	if (dp[sum][n][m])return dp[sum][n][m]%1000000007;
	if (sum == 1 && n == N && m == M - 1)return 1;
	dp[sum][n][m] =(dfs(2 * sum, n + 1, m) + dfs(sum - 1, n, m + 1))%1000000007;
	return dp[sum][n][m];
}
int main() {
	memset(dp, 0, sizeof(dp));
	cin >> N >> M;
	cout << dfs(2, 0, 0);
}

动态规划参考:
https://blog.csdn.net/AC__dream/article/details/124072351

试题J:砍竹子

​ 时间限制:1.0s 内存限制:256.0MB 本题总分:25分
【问题描述】
​ 这天,小明在砍竹子,他面前有n棵竹子排成一排,一开始第i棵竹子的高度为hi他觉得一棵一棵砍太慢了,决定使用魔法来砍竹子。魔法可以对连续的一段相同高度的竹子使用,假设这一段竹子的高度为H,那么使用一次魔法可以把这一段竹子的高度都变为 ⌊ ( ⌊ H 2 ⌋ + 1 ) ⌋ \lfloor \sqrt(\lfloor \frac{H}{2}\rfloor+1) \rfloor ( 2H+1)⌋其中 ⌊ x ⌋ \lfloor x \rfloor x表示对x向下取整。小明想知道他最少使用多少次魔法可以让所有的竹子的高度都变为1。
【输入格式】
​ 第一行为一个正整数n,表示竹子的棵数。
​ 第二行共n个空格分开的正整数h,表示每棵竹子的高度。
【输出格式】
​ 一个整数表示答案。
【样例输入】

6
2 1 4 2 6 7

【样例输出】

5

【样例说明】
其中一种方案:

 2 1 4 2 6 7
→2 1 4 2 6 2
→2 1 4 2 2 2
→2 1 1 2 2 2
→1 1 1 2 2 2 
→1 1 1 1 1 1

共需要5步完成
【评测用例规模与约定】
对于20%的数据,保证n≤1000,hi≤10^6。
对于100%的数据,保证n≤2×10^5 ,hi≤10^18

注意:魔法只能和相邻竹子一起使用

#include<iostream>
#include<cmath>
using namespace std;
int a[200000];

int GetMax(int n) {
	int max = 0;
	for (int i = 0; i < n; i++)  //求最大值
		max = (a[i]>= max?a[i]:max);
	return max;
}
int main() {
	int n, num = 0, max = 0, t;
	cin >> n;
	for (int i = 0; i < n; i++)  	cin >> a[i];
	max=GetMax(n);
	
	while (max != 1) {
		 
		/*魔法只在相邻位生效*/
		for (int i = 0; i < n; i++) { //最大值全部替换
			if (a[i] == max && a[i + 1] == max) {
				a[i] = floor(sqrt(max / 2 + 1));
			}
			else if (a[i] == max && a[i + 1] != max) {
				a[i] = floor(sqrt(max / 2 + 1));
				break;
			}
		}
		max=GetMax(n);
		num++;
	}
	cout << num;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值