综述由AI生成第十三届蓝桥杯省赛 C/C++ 大学 B 组的 10 道真题题解与解析,涵盖进制转换、贪心算法、动态规划、搜索及基础数学运算等核心考点。主要涉及九进制转十进制、顺子日期、刷题统计、修剪灌木、X 进制减法、统计子矩阵、积木画、扫雷、李白打酒加强版及砍竹子等题目。提供了完整的 C++ 代码实现及关键知识点总结,包括数据类型选择、内存分配策略及常用库函数用法,适合备考选手参考学习。
人间失格21 浏览
第十三届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组题解
本文整理了第十三届蓝桥杯省赛 C/C++ 大学 B 组的 10 道真题题解与解析,涵盖进制转换、贪心算法、动态规划、搜索及基础数学运算等核心考点。
问题描述
小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a 道题目,周六和周日每天做 b 道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于 n 题?
解析
注意数据范围可能达到 10^18,不能直接循环累加,需利用整除和取模优化。
#include<bits/stdc++.h>#define int long longusingnamespace std;
signedmain(){
int a,b,n;
cin>>a>>b>>n;
int cnt = 0;
int sum = n/(a*5+b*2);
int temp = n%(a*5+b*2);
if(temp<=a*5){
cnt+=ceil((double)temp/a);
}else{
temp-=5*a;
cnt+=5;
cnt+=ceil((double)temp/b);
}
cnt+=sum*7;
cout<<cnt<<endl;
return0;
}
4. 修剪灌木
问题描述
有 N 棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晚会修剪一棵灌木,让灌木的高度变为 0 厘米。修剪顺序是从最左侧开始向右,修完最右侧后调转方向向左,循环往复。灌木每天从早上到傍晚会长高 1 厘米。求每棵灌木最高长到多高。
解析
贪心观察,第 i 棵树(0-indexed)最高高度为 max(i*2, (N-i-1)*2)。
#include<bits/stdc++.h>usingnamespace std;
#define int long longconstint N = 5e2 + 5;
int arr[N][N];
int n, m, K;
signedmain(){
cin >> n >> m >> K;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cin >> arr[i][j];
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
arr[i][j] += arr[i][j - 1];
for (int j = 1; j <= m; ++j)
for (int i = 1; i <= n; ++i)
arr[i][j] += arr[i - 1][j];
int cnt=0;
for(int top=0; top<=n; ++top){
for(int bott=top+1; bott<=n; ++bott){
int l=0;
for(int r=1; r<=m; ++r){
int sum= arr[bott][r]-arr[bott][l]-arr[top][r]+arr[top][l];
while(sum>K&&l<r){
l++;
sum= arr[bott][r]-arr[bott][l]-arr[top][r]+arr[top][l];
}
cnt+=r-l;
}
}
}
cout << cnt << endl;
return0;
}
7. 积木画
问题描述
用 I 型(2 单位面积)和 L 型(3 单位面积)积木拼满 2×N 的画布,求方案数。
解析
线性 DP。定义状态 dp[i][0/1/2] 分别表示第 i 列第一行填满、两行都填满、第二行填满的方案数。
#include<bits/stdc++.h>#define int long longusingnamespace std;
constint MOD = 1000000007;
constint N = 1e7+5;
int dp[N][3];
signedmain(){
int n;
cin>>n;
dp[0][1]=1;
dp[1][1]=1;
for(int i=2; i<=n; ++i){
dp[i][0]=(dp[i-1][2]+dp[i-2][1])%MOD;
dp[i][2]=(dp[i-1][0]+dp[i-2][1])%MOD;
dp[i][1]=((dp[i-1][0] + dp[i-1][2])%MOD + (dp[i-1][1] + dp[i-2][1])%MOD)%MOD;
}
cout<<dp[n][1]<<endl;
return0;
}
8. 扫雷
问题描述
在一个 n 行 m 列的方格图上有一些位置有地雷,请为每个空位置标一个整数,表示周围八个相邻的方格中有多少个地雷。
解析
模拟遍历,对每个格子检查周围 8 个方向是否有地雷。
#include<bits/stdc++.h>usingnamespace std;
#define int long longconstint N = 1e2+5;
vector<vector<int>> arr(N,vector<int>(N,0));
vector<vector<int>> res(N,vector<int>(N,0));
int n,m;
int fa1[]={1,1,0,0,-1,1,-1,-1};
int fa2[]={-1,1,1,-1,0,0,1,-1};
signedmain(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1; i<=n; ++i)
for(int j=1; j<=m; ++j)
cin>>arr[i][j];
for(int i=1; i<=n; ++i){
for(int j=1; j<=m; ++j){
if(arr[i][j]!=0) res[i][j]=9;
else{
int sum=0;
for(int k=0; k<8; ++k){
if(arr[i+fa1[k]][j+fa2[k]]!=0) sum++;
}
res[i][j]=sum;
}
}
}
for(int i=1; i<=n; ++i){
for(int j=1; j<=m; ++j) cout<<res[i][j]<<" ";
cout<<endl;
}
return0;
}
9. 李白打酒加强版
问题描述
李白提壶买酒,初始 2 斗。逢店加一倍,遇花喝一斗。一共遇到店 N 次,花 M 次,最后一次是花,正好喝完。求不同顺序的方案数。
解析
记忆化搜索或动态规划。dfs(n, m, drink) 表示剩余店数、花数和当前酒量。
#include<bits/stdc++.h>usingnamespace std;
#define int long longconstint MOD = 1000000007;
int used[105][105][105];
int n,m,drink;
intdfs(int n,int m,int drink){
if(n<0||m<0||drink<0) return0;
if(drink>m) return0;
if(n==0&&m==1&&drink==1) return1;
if(used[n][m][drink]!=-1) return used[n][m][drink];
return used[n][m][drink]=(dfs(n-1,m,drink*2)+dfs(n,m-1,drink-1))%MOD;
}
signedmain(){
cin>>n>>m;
memset(used,-1,sizeof used);
drink = 2;
cout<<dfs(n,m,drink);
return0;
}
10. 砍竹子
问题描述
有 n 棵竹子,高度 hi。魔法可以对连续相同高度的竹子使用,一次魔法可将高度 H 变为 floor(H/2)+1。求最少使用多少次魔法使所有竹子高度变为 1。
解析
优先队列维护当前最大高度,处理连续相同高度的竹子。
#include<bits/stdc++.h>#define int long long#define x first#define y secondusingnamespace std;
structcmp{
booloperator()(const pair<int,int>& p1,const pair<int,int>& p2){
if(p1.x==p2.x) return p1.y>p2.y;
return p1.x<p2.x;
}
};
intget_res(int cnt){
returnfloor(sqrtl(floor(double(cnt)/2)+1));
}
signedmain(){
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> pq;
int n;
cin>>n;
for(int i=0; i<n; ++i){
int num;
cin>>num;
pq.emplace(num,i);
}
int cnt=0;
int temp_id=-2,temp_cnt=-2;
while(!pq.empty()){
auto cur = pq.top();
pq.pop();
if(cur.x==1) continue;
if(temp_id==cur.y-1&&temp_cnt==cur.x){
temp_id=cur.y;
int val = get_res(cur.x);
if(val!=1) pq.emplace(val,temp_id);
}else{
cnt++;
temp_cnt=cur.x;
temp_id =cur.y;
int val = get_res(cur.x);
if(val!=1) pq.emplace(val,temp_id);
}
}
cout<<cnt;
return0;
}
知识点总结
一、double 与 long double
double: 通常占用 8 字节,有效位数约为 15~17 位。
long double: 编译器决定,通常不少于 double,在某些架构下占 12 或 16 字节,有效位数 18-19 位。