2024年第十五届蓝桥杯C/C++C组题目全解首发(AK)

本文介绍了五个C++编程题目,涉及正方形拼接、连续匹配、数字诗意、封闭图形个数、回文数组操作、商品库存管理和挖矿问题。文章详细解析了题目的思路和解答方法,展示了算法应用和优化技巧。
摘要由优快云通过智能技术生成

五一假期,记vp一场c++c组的题目..

A: 拼正方形(结果填空)

题意:给a个2*2的方格,b个1*1的方格,问能凑成的最大正方形边长;

思路:4a+1b开根号就是答案,前提是b得是偶数且是四的倍数,不妨先将b个1*1的方格凑成2*2的,然后2*2的格子数*4后开方,就是答案;

答案:5435122


B: 劲舞团(结果填空)

题意:给2000行记录,求最长连续匹配数,匹配是指:当前记录中 第一二个字符一样 且和上一条记录(同匹配)之间的时间戳差值小于1s;

思路:

答案:9


C: 数字诗意

题意:给一个数列,问数列中有多少个数是属于一个前n项和的结果(n>=2)。

思路:数据范围显然不可能是枚举a_in,很可能需要位运算,如图,打表找规律,发现只有2的整数次幂才不满足,2的54次方刚好大于了|ai|的数据范围1e16, 所以只需要对枚举54位,数列中恰好等于k次方的数的个数就是答案。

复杂度:O(N)

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;

int main(){ 
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int m,res = 0; cin >> m;
	for (int i = 1; i <= m; i ++){
		ll x; cin >> x;
		for (int j = 0; j <= 54; j ++){
			if (x == pow(2,j)) res ++;
		}
	}
	cout << res <<"\n";

	return 0;
}

D: 封闭图形个数

题意:给10以内数字加一个基础属性,0,4,6,9数字属性值是1,8的属性值是2,1,2,3,5,7的属性值是0,现给一个数列,要求按照属性值大小排序,若属性值大小相同,则输出数字本身大小

思路:结构体基础知识,重构小于号(手写sort的cmp也可以),直接把一个数字按数位拆出来然后叠加属性值就可以了,最后将数列按从小到大顺序输出。

复杂度:O(N)

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n;
const int N = 2e5+10;
struct Nod{
	int w;
	bool operator < (const Nod &k) {
		int r1=0,r2=0;
		int m1 = w, m2 = k.w;
		while (m1){
			int x = m1%10;
			r1+=((x==0)||(x==4)||(x==6)||(x==9));
			r1+=((x==8)*2);
			m1/=10;
		}
		while (m2){
			int x = m2%10;
			r2+=((x==0)||(x==4)||(x==6)||(x==9));
			r2+=((x==8)*2);
			m2/=10;
		}
		if (r1==r2) return w < k.w;
		return r1 < r2;
	}
}arr[N];

int main(){ 
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin >> n;	
	for (int i = 1; i <= n; i ++) cin >> arr[i].w;
	sort(arr+1, arr+n+1);
	for (int i = 1; i <= n; i ++) cout << arr[i].w << " ";
	return 0;
}

E:回文数组

题意:给一个数列,有两个操作,一是将单个数字+1或-1,二是将相邻的两个数字同时+1或者-1,问最后将其修改为回文数列的最小修改次数。

思路:回文相关的问题一般都具有对称性,考虑第i个数和考虑第n-i+1个数问题一样,可以忽略后者,因此这里只需要处理前一半。贪心,假设现在处理的第j个数与第n-j+1个数的差值 和 即将处理的第j+1个数与第n-(j+1)+1个数的差值同号,那么就可以用操作二一次性处理,剩下的就只能是操作1了。

复杂度:O(N)

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
ll a[N],p[N];
ll res = 0;
int main(){ 
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n; cin >> n;	
	for (int i = 1; i <= n; i ++) cin >> a[i];
	for (int i = 1, j = n; i < j; i ++, j --) p[i] = a[j] - a[i];
	for (int i = 1; i <= n/2; i ++){
		res += abs(p[i]); // 异号单独加
		if (p[i]>0 && p[i+1]>0) p[i+1]-=min(p[i],p[i + 1]); // 同号一起处理
		if (p[i]<0 && p[i+1]<0) p[i+1]-=max(p[i],p[i + 1]);
	}
	cout << res << "\n";
	return 0;
}

F: 商品库存管理

题意:给一个全0数列,有m次操作,每次给数列中一段区间+1,求分别撤销第i次操作后,数列中0的个数。

思路:差分+前缀和。先差分所有操作,然后记录一下当前数列当中0的个数r0,因为差分后是0的数,无论撤销哪一次操作,都不会变。随后,结合题意,假定撤销某次区间[l,r]操作之后aj=0(l<=j<=r),那么也就意味着a_j在这个区间操作被撤销之前必定是1,显然,问题可以转化为:求m个区间当中1的个数。将差分后的数组中的1拎出来做前缀和,然后分别算每个操作区间当中1的个数就可以了,记得每次都要加上r0。

复杂度:O(M+N)

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n,m;
const int N = 300010;
typedef pair<int,int> PII;
PII ts[N];
int bs[N],pre[N]; 
int ret = 0; 
int main(){ 
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin >> n >> m;	
	for (int i = 1; i <= m; i ++){
		cin >> ts[i].first >> ts[i].second; 
		bs[ts[i].first]++,bs[ts[i].second+1]--;
	}
	for (int i =1;i<=n;i++) bs[i]+=bs[i-1], ret += (bs[i]==0); 
	for (int i =1;i<=n;i++) pre[i]+=pre[i-1]+(bs[i]==1);
	for (int i = 1; i <= m; i ++){
		int l = ts[i].first, r = ts[i].second; 
        cout << pre[r]-pre[l-1]+ret <<"\n";
	}
	return 0;
}

G: 挖矿

题意:在一维数轴上,给若干个指定坐标x和m,从起始点出发,每次可以朝左边/右边走一个单位,问不超过距离m最多能走到多少个不同的指定坐标。

思路:先预处理一个往左右两边走分别能包含坐标数的前缀和,g[0][i]表示从起始点往左走i个单位长度能包含多少个指定坐标,g[1][i]表示从起始点往右走i个单位长度能包含多少个指定坐标。

        接着分析,假设有x_3>x_2>x_1>0(小于0的情况也一样,对称的),若x_2能被包含到答案里面,那么一定是从x_1走过来,而不可能从x_3走过来,这里也不难证明,假设从x_3x_2的路线是优的,那从起始点出发到x_3是优的、从起始点到x_2也是优的,显然与前一命题产生矛盾,所以每一个指定坐标只需要考虑是否能从比自己小的坐标走过来。

        其次讨论不同情况:情况1:从起始点一直往左走能找到解,答案就是g[0][m];情况2是情况1的镜像,答案是g[1][m]; 情况3:从起始点往左走i个单位,然后往回到起点再往右走(m-2*i>0)个单位;情况4也是情况3的镜像。

        可以发现,情况1、2其实是可以和3、4合并的(情况3、4枚举往左/右走的单位长度,当单位长度是m的时候其实就是情况1和2,能往反方向走当且仅当m-2*i>0)。

复杂度:O(N)

#include <iostream>
#include <algorithm>
using namespace std;
int n,m;
const int N = 1e5+10, M = 2e6 + 10;
typedef long long ll;
ll g[2][M];

int main(){ 
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin >> n >> m;	
	for (int i = 1; i <= n; i ++){
		int x;cin>>x;
		if (x<0)  g[0][-x]=1;
		if (x>=0)  g[1][x]=1;
	}

	// 前缀和 往左右走i步有多少个宝石
	for (int i = 1; i <= m; i ++) {
		g[0][i]+=g[0][i-1];
		g[1][i]+=g[1][i-1];
	}
	
	ll Lres = 0;
	for (int i = 1; i <= m; i ++){
		ll dis = g[0][i];
		if (m-2*i>0) dis += g[1][m - 2*i];
		Lres = max(Lres,dis);
	}

	ll Rres = 0;
	for (int i = 1; i <= m; i ++){
		ll dis = g[1][i];
		if (m-2*i>0) dis += g[0][m - 2*i];
		Rres = max(Rres,dis);
	}
	
	cout << max(Lres,Rres) << "\n";
	
	return 0;
}

H: 回文字符串

题意:给一个字符串,可以在开头处加入任意数目个指定字符l/q/b,问能否将字符串转化为一个回文字符串。

思路:基础题实锤。既然能在字符串前面加入任意数目个l/q/b,那字符串最后面的l/q/b完全可以忽略,因为一定可以配对,问题转化为:删掉给定字符串最后面的l/q/b字符,问剩下的字符是否是回文串,评测一共是10组数据,一组字符串长度最大是1e6,也就是1e7的复杂度,On可以随便写,同时从两边遍历中间,发现对应不上就直接停止。

复杂度:O(N)

#include <iostream>
#include <algorithm>
using namespace std;
void solve(){
	string s; cin >> s;
	int pos = s.length()-1;
	for (; pos; pos --){
		if (s[pos]!='l' && s[pos] !='q' && s[pos]!='b') break;
	}
	string tmp = s.substr(0, pos+1); // 去掉后面那一串前面可以任意堆叠的 
	bool fg = true;
	for (int i = 0,j = tmp.length()-1; i <= j; i ++, j --){ // 看看剩下的是不是回文串就可以了 复杂度On 1E7数据1秒随便跑
		if (tmp[i] != tmp[j]){
			fg = false; 
			break;
		}
	}
	cout << (fg ? "Yes" : "No") << "\n";
}

int main(){ 
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int t; cin >> t;
	while (t--){
		solve();
	}
	return 0;
}

Finally:测评成绩

以上仅为oj平台的测评结果( 评测OJ:首页 - DashOJ),若有最优解或者Hack数据欢迎在评论区讨论;

最后的最后,祝大家五一假期快乐!

### 关于2024蓝桥杯省赛C语言B的信息 #### 比赛规则概述 对于参赛者而言,了解最新的比赛规则至关重要。通常情况下,蓝桥杯竞赛会提前公布详细的规则手册给各参赛学校和个人选手。该手册涵盖了考试形式、评分标准以及注意事项等内容[^1]。 #### 历史题解分析 回顾往的试题有助于预测可能遇到的问题类型并制定有效的复习策略。例如,在第十届比赛中出现了涉及字符串处理、数操作等多个知识点的考题;而到了2022,则增加了算法复杂度的要求,部分题目达到了国家级别的挑战水平[^2]。通过研究这些变化趋势可以更好地为即将到来的比赛做准备。 #### 备战建议与资源推荐 为了迎接更高层次的竞争环境,考生应该注重以下几个方面: - **基础知识巩固**:熟练掌握数据结构(链表、栈队列)、基本算法设计模式(分治法、贪心算法)等核心概念。 - **编程实践训练**:多参与在线评测平台上的模拟测试活动,积累实战经验的同时提高代码质量。 - **历真题演练**:深入剖析历届优秀解答案例,学习他人解决问题的独特思路和技术手段[^3]. ```c // 示例:简单的快速排序实现用于练习基础技能 void quickSort(int arr[], int low, int high){ if (low < high){ /* pi is partitioning index */ int pi = partition(arr, low, high); // Recursively sort elements before and after partition quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值