分享缩略图

分享到:
链接已复制
首页> 新闻中心>

第十五届蓝桥杯省赛C/C++大学B组真题及赛后总结

2025-06-24 12:36:55

来源:新华网

字体:

目录

 

个人总结

C/C++ 组真题

握手问题

小球反弹

好数

R 格式

宝石组合

数字接龙

爬山

拔河

​编辑

再总结及后续规划、名次


 

个人总结

第一次参加蓝桥杯,大二,以前都在在学技术,没有系统的学过算法。所以,还是花了挺多时间去备战的,因为暑假想找实习,就想拿个奖写简历上。备战了大概一个多月,学了一些基础的算法(dfs bfs 动态规划为主),刷了快200道题吧,但还是因为缺少经验,比赛时有点茫然了,然后大概率是寄了。

C/C++ 组真题

握手问题

4d3bc142600e4bb7b9402fb420823553.png

这道第一题相对于去年还算是比较简单,排列 + 特殊情况处理即可

(50 * 49) / 2 - (6*7) / 2 = 1204,答案应该是正确的

小球反弹

e5ed0cbfb44d4fb1932d744da5073a50.png

这个应该是错了哈哈,答案是 1100325199.77,但和这个值挺像的,可惜只看答案。

前两道题都是数学问题,唉,后悔没有静下心来看第二题了。

好数

5f382e0ebe874c25951e365dfc373b00.png

e4c259f207d94a0eb9074eb5f56b0937.png

160bcbe483e84cc9b6575e89fb87622b.png

这道题直接暴力模拟即可,数据量没有很大。

#include <iostream>using namespace std;int N;int main(){ 	cin >> N;	int Count = 0; // 记录总个数	for (int i = 1; i <= N; i++)	{ 		// 判断某一个数是否是 好数		int n = i; // 用 n 记录 i		int flag = 1; // 1 此时计算的是 i 的奇数位, 0 表示此时计算的是 i 的偶数位		int ret = 1; // 记录当前数否为 好数		while (n > 0)		{ 			int end = n % 10;			if (flag == 1)			{ 				if (end % 2 == 0)				{ 					ret = 0;					break;				}				flag = 0;			}			else //  flag = 0			{ 				if (end % 2 != 0)				{ 					ret = 0;					break;				}				flag = 1;			}			n /= 10;		}		if (ret == 1) Count++;	}	cout << Count << endl;	return 0;}

R 格式

348668c6a3ca4f51a659c367bfd0c231.png 2c7644a828c744069bb13ffcfe46d439.png

5744f4a98705446788edf24219733b3c.png

这道题看起来挺简单的,但如果要拿满分的话,需要使用字符串模拟,我直接使用 long long 了,应该能拿 50% 的分。

long long  50%代码

#include using namespace std;double d;int n;long long func(int n){ 	long long ret = 1;	while (n--)	{ 		ret *= 2;	}	return ret;}int main(){ 	cin >> n >> d;	cout << (long long)(func(n) * d + 0.5) << endl;	return 0;}

宝石组合

de0fb3a352594e889d0dca13e5d0a900.png

a5f118e289cb467ea6436e102d5e26f2.pngba8f969eeaad4709bcfa32b8b043b218.png

 这道题没有学过网上的那些公式算法,第一个想到的是暴击解法,时间复杂度O(N^3),但思考了一会,发现是可以用哈希表来优化的,时间复杂度可以降到 O(N^2)。不过貌似依然过不了很多数据,第二个比较麻烦的点就是如果 S 相同的情况下要按字典序排顺序。

#include #include #include using namespace std;long long N;long long nums[100010];long long func(long long a, long long b, long long c = 1){ 	long long Max = max(a, max(b, c));	long long i = 0;	for (i = Max; i >= 0; i += Max)	{ 		if (i % a == 0 && i % b == 0 && i % c == 0) break;	}	return i;}long long get_S(long long a, long long b, long long c){ 	long long tmp = a * b * c * func(a, b ,c);	long long ret = tmp / (func(a, b) * func(a, c) * func(b, c));	return ret;}int main(){ 		cin >> N;	for (long long i = 1; i <= N; i++) cin >> nums[i];	unordered_map> hash;	for (long long i = 2; i <= N; i++)	{ 		for (long long j = i - 1; j >= 1; j--)			hash[nums[i] * nums[j]] = {  j, i };	}	long long ret[3] = { 100010, 100010, 100010};	long long S = 0;	for (long long i = 1; i <= N; i++)	{ 		for (auto& e : hash)		{ 			if (e.second.first != i && e.second.second != i)			{ 				long long tmp = get_S(nums[i], nums[e.second.first], nums[e.second.second]);				if (tmp > S)				{ 					S = tmp;					ret[0] = nums[i];					ret[1] = nums[e.second.first];					ret[2] = nums[e.second.second];				}				else if (tmp == S)				{ 					if (ret[0] > nums[i])					{ 						ret[0] = nums[i];						ret[1] = nums[e.second.first];						ret[2] = nums[e.second.second];					}					else if (nums[i] == ret[0] && ret[1] > nums[e.second.first])					{ 						ret[0] = nums[i];						ret[1] = nums[e.second.first];						ret[2] = nums[e.second.second];					}					else if (nums[i] == ret[0] && ret[1] == nums[e.second.first] && ret[2] > nums[e.second.second])					{ 						ret[0] = nums[i];						ret[1] = nums[e.second.first];						ret[2] = nums[e.second.second];					}				}			}		}	}	cout << ret[0] << " " << ret[1] << " " << ret[2] << endl;	return 0;}

数字接龙

a276a26b0ee74725a637f4afe1d5aad5.png

240f3c4bd58a4bef9f629072515c4145.png

这道题,打眼一看是 dfs ,觉得自己会,就开始做,没想到做到最后,不会判断路径是否交叉,有点懵逼了,就直接将得到的所有可以走完的路径按字典序排序后取了第一个,最后估计还没有直接输出 - 1的人得的分多。还是比赛经验不够,应该先好好看完题再开始写代码的。

这里就不放我的错代码了,唉,看到正确答案就在自己负责调试的 vector 里,却没有办法去除错错误的答案...

知乎正确答案:

#include #include using namespace std;const int N = 11;int a[N][N];int dt[8][2] = {  { -1,0},{ -1,1},{ 0,1},{ 1,1},{ 1,0},{ 1,-1},{ 0,-1},{ -1,-1} };int n, k;vector path;vector res;bool ban[N][N][N][N];bool vis[N][N];void dfs(int sx, int sy){ 	if (!res.empty()) return;	if (sx == n - 1 && sy == n - 1)	{ 		if (path.size() == n * n - 1) res = path;		return;	}	if (path.size() == n * n - 1) return;	for (int i = 0; i < 8; i++)	{ 		if (!res.empty()) return;		int dx = dt[i][0], dy = dt[i][1];		int x = sx + dx, y = sy + dy;		if (x >= 0 && x < n && y >= 0 && y < n && !vis[x][y] && a[x][y] == (a[sx][sy] + 1) % k)		{ 			if (dx != 0 && dy != 0 && ban[sx + dx][sy][sx][sy + dy]) continue;			ban[sx][sy][x][y] = ban[x][y][sx][sy] = true;			vis[x][y] = true;			path.push_back(i);			dfs(x, y);			path.pop_back();			vis[x][y] = false;			ban[sx][sy][x][y] = ban[x][y][sx][sy] = false;		}	}}int main(){ 	scanf("%d%d", &n, &k);	for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) scanf("%d", &a[i][j]);	vis[0][0] = true;	dfs(0, 0);	if (!res.empty())	{ 		for (auto x : res) printf("%d", x);	}	else	{ 		puts("-1");	}	return 0;}

爬山

af2af1da41684ca4acc3b206f32d2a47.png

8973595d108744988062ef69598f97fa.png 由于上一题浪费了太多时间,这道题也没有认真看,想了一下动态规划,感觉有点复杂,凭感觉写了一下...出来后看了答案才发现是 优先级队列 + 贪心

这是知乎上的贪心答案,但这个做法对于有的测试用例也是过不了的,我感觉还是应该用动态规划哈哈。

int main(){ 	priority_queue heap;	scanf("%d%d%d",&n,&P,&Q);	for(int i=1;i<=n;i++) scanf("%d",&a[i]),heap.push(a[i]);	while(P||Q)	{ 		auto x=heap.top();		heap.pop();		if(P&&Q)		{ 			int yl=_sqrt(x);			int y2=x/2;			if(y2<=yl)			{ 				Q--;				heap.push(y2);			}			else			{ 				P--;				heap.push(yl);			}		}		else if(P)		{ 			int yl=_sqrt(x);			P--;			heap.push(yl);		}		else		{ 			int y2=x/2;			Q--;			heap.push(y2);		}	}	ll res=0;	while(!heap.empty())	{ 		int x=heap.top();		heap.pop();		res+=x;	}	printf("%lld\n",res);	return 0;}

拔河

41b95040a9c2402fb29b346d063c207c.png

27aeb7c9ac4543d9b2909e42f180f68d.png

这道题看都没看,唉,应该先看一下的......,起码得个暴力分

标准答案:指针 + 二分

#include #include #include using namespace std;typedef long long ll;const int N = 1003;int a[N];int n;ll s[N];int main(){ 	scanf("%d", &n);	for (int i = 1; i <= n; i++) scanf("%d", &a[i]), s[i] = s[i - 1] + a[i];	multiset S;	for (int l = 1; l <= n; l++)	{ 		for (int r = l + 1; r <= n; r++)		{ 			S.insert(s[r] - s[l]);		}	}	ll res = 0x3f3f3f3f;	for (int r = 1; r < n; r++)	{ 		for (int l = 0; l < r; l++)		{ 			ll val = s[r] - s[l];			auto it = S.lower_bound(val);			if (it != S.end())			{ 				ll ans = abs(*it - val);				res = min(res, ans);			}			if (it != S.begin())			{ 				it--;				ll ans = abs(*it - val);				res = min(res, ans);			}		}		for (int r2 = r + 1; r2 <= n; r2++)		{ 			S.erase(S.find(s[r2] - s[r]));		}	}	printf("%lld\n", res);	return 0;}

再总结及后续规划、名次

总结:自己算法还是太菜了(毕竟练习时长只有一个月),本次大概率可能是省二 ~ 省三了,省一的概率不大,不知道大三还有没有机会再打蓝桥杯,那时候应该要实习 / 考研吧。

接下来的安排,下周六还有一场天梯赛,打完后就要继续学技术了,冲一下暑假的日常实习,到时候就开始佛系做力扣每日一题了,不再花时间集中学算法了,算法竞赛的帮助,对于找开发的工作,有帮助,但最重要的还是技术得学到手,做项目。

最后的名次:省一中游

 

【责任编辑:新华网】
返回顶部