- 第 202 篇 -
Date: 2026 - 04 - 06~08 | 周一~周三
Author: 郑龙浩(仟墨)
今日练习:蓝桥杯第13届省赛B组Cpp组 10道题
6号刷题后,7号弄懂了大半错题,8号解决了剩下的部分。虽然DP题型仍不太理解,但我决定先放一放,转而练习贪心算法去了,因为贪心一直没有练习。考虑到蓝桥杯只剩两天,最后8号(今天)晚上我决定集中复习之前做过的题目。
2026-04-06~08-算法打卡day38day39-蓝桥杯第13届省赛B组Cpp组
文章目录
- 2026-04-06~08-算法打卡day38day39-蓝桥杯第13届省赛B组Cpp组
- 1-九进制转十进制
- 2-顺子日期
- 3-刷题统计
- 4-修剪灌木
- 5-X进制减法
- 6-统计子矩阵
- 7-积木画
- 8-扫雷
- 9-李白打酒加强版
- 10-砍竹子
1-九进制转十进制
全对
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
九进制正整数 (2022)9(2022)9 转换成十进制等于多少?
- 最大运行时间:1s
- 最大运行内存: 512M
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 1-九进制转十进制
* Author:郑龙浩
* Date:2026-04-06
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << 2 * pow(9, 0) + 2 * pow(9, 1) + 2 * pow(9, 3);
return 0;
}
2-顺子日期
0分
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456 等。顺子日期指的就是在日期的 yyyymmdd 表示法中,存在任意连续的三位数是一个顺子的日期。例如 20220123 就是一个顺子日期,因为它出现了一个顺子:123; 而 20221023 则不是一个顺子日期,它一个顺子也没有。小明想知道在整个 2022 年份中,一共有多少个顺子日期?
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
0分版本
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 2-顺子日期-0分
* Author:郑龙浩
* Date:2026-04-06
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// 22 年是平年
int months[13] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
string s;
int cnt = 0;
for (int i = 1; i < 13; i++) {
for (int j = 1; j <= months[i]; j++) {
if (i > 9 && j > 9) s = "2020" + to_string(i) + to_string(j);
else if (i > 9 && j < 10) s = "2020" + to_string(i) + '0' + to_string(j);
else if (i < 10 && j > 9) s = "2020" + '0' + to_string(i) + to_string(j);
else if (i < 10 && j < 10) s = "2020" + '0' + to_string(i) + '0' + to_string(j);
for (int k = 0; k <= s.size() - 3; k++) {
if (s[k] != '0' && s[k] + 1 == s[k + 1] && s[k + 1] + 1 == s[k + 2]) { cnt++; break;}
}
}
}
cout << cnt;
return 0;
}
修改后
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 2-顺子日期-修改版
* Author:郑龙浩
* Date:2026-04-06
* 错因1:months忘记在开头写0了
* 错因2:2022写错为了2020
* 错因3:"2022" + '0' 并不是20220,而是2022字面量奖赏'0'的ASCII值48,得出-->d,导致存储的不是字符串拼接,而是2022字面量+'0'ASCII
* 我后来改成了 "2022" + "0"也是错误的,因为两个字面量相加就不对,应该将其中一个改为string,这样就是string + 字面量,而不是字面量+字面量了
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// 22 年是平年
int months[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
string s;
int cnt = 0;
for (int i = 1; i < 13; i++) {
for (int j = 1; j <= months[i]; j++) {
if (i > 9 && j > 9) s = "2022" + to_string(i) + to_string(j);
else if (i > 9 && j < 10) s = "2022" + to_string(i) + "0" + to_string(j);
else if (i < 10 && j > 9) s = "2022" + string("0") + to_string(i) + to_string(j);
else if (i < 10 && j < 10) s = "2022" + string("0") + to_string(i) + "0" + to_string(j);
// 错误代码2:在C++中不允许出现"2022" + "0",因为这个是两个字符串字面量的加法,不允许链接两个const char*指针
// 不能直接对两个字符串字面量使用 +运算符
// else if (i < 10 && j > 9) s = "2022" + "0" + to_string(i) + to_string(j);
// else if (i < 10 && j < 10) s = "2022" + "0" + to_string(i) + "0" + to_string(j);
// 错误代码1:不能 string 字面量 + ASCII
// else if (i > 9 && j < 10) s = "2022" + to_string(i) + '0' + to_string(j);
// else if (i < 10 && j > 9) s = "2022" + '0' + to_string(i) + to_string(j);
// else if (i < 10 && j < 10) s = "2022" + '0' + to_string(i) + '0' + to_string(j);
for (int k = 0; k <= s.size() - 3; k++) {
if (s[k] + 1 == s[k + 1] && s[k + 1] + 1 == s[k + 2]) {cnt++; break;}
}
}
}
cout << cnt;
return 0;
}
3-刷题统计
10个案例过4个
问题描述
小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天 做 aa 道题目, 周六和周日每天做 bb 道题目。请你帮小明计算, 按照计划他将在 第几天实现做题数大于等于 nn 题?
输入格式
输入一行包含三个整数 a,ba,b 和 nn.
输出格式
输出一个整数代表天数。
样例输入
10 20 99
样例输出
text
8
评测用例规模与约定
对于 50%50% 的评测用例, 1≤a,b,n≤1061≤a,b,n≤106.
对于 100%100% 的评测用例, 1≤a,b,n≤10181≤a,b,n≤1018.
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
10个案例过4个
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 3-刷题统计-10案例过4个
* Author:郑龙浩
* Date:2026-04-06
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a, b, n;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> a >> b >> n;
int zhouji = 1;
ll sum = 0;
for (ll day = 1; ; day++, zhouji = (zhouji + 1) % 8) {
if (zhouji == 6 || zhouji == 7) sum += b;
else sum += a;
if (sum >= n) {cout << day; return 0;}
}
return 0;
}
全对版本
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 3-刷题统计-修改版
* Author:郑龙浩
* Date:2026-04-07修改
* 错因1: (zhouji + 1) % 8 会让周几在0~7之间循环,明显错误
* 错因2:当n为1e18的时候,明显会超时
* 修改方法:直接计算可以解决多少个以7天为单位的题目,然后只循环最后一周
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
/*
ll a, b, n;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> a >> b >> n;
// 修改前:int zhouji = 1;
int zhouji = 0;
ll sum = 0;
// 错误代码:这样day会在0~7之间徘徊,所以不对
for (ll day = 1; ; day++, zhouji = (zhouji + 1) % 8) {
if (zhouji == 6 || zhouji == 7) sum += b;
else sum += a;
if (sum >= n) {cout << day; return 0;}
}
return 0;
}*/
ll a, b, n;
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> a >> b >> n;
int totalWeek = a * 5 + b * 2; // 一周可以做的题的数量
ll totalDay = n / totalWeek * 7; // 总做题天数,7天都做
ll remaining = n % totalWeek; // 还剩多少题没做
if (remaining == 0) {cout << totalDay; return 0;}
for (int day = 0; ; day = (day + 1) % 7) { // 0~6对应1~7周
totalDay++;
if (day == 5 || day == 6) remaining -= b;
else remaining -= a;
if (remaining <= 0) {cout << totalDay; return 0;}
}
}
4-修剪灌木
8案例过3-内存太大
问题描述
爱丽丝要完成一项修剪灌木的工作。
有 NN 棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晩会修剪一棵灌 木, 让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始, 每天向右修剪一棵灌木。当修剪了最右侧的灌木后, 她会调转方向, 下一天开 始向左修剪灌木。直到修剪了最左的灌木后再次调转方向。然后如此循环往复。
灌木每天从早上到傍晩会长高 1 厘米, 而其余时间不会长高。在第一天的 早晨, 所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。
输入格式
一个正整数 NN, 含义如题面所述。
输出格式
输出 NN 行, 每行一个整数, 第 ii 行表示从左到右第 ii 棵树最高能长到多高。
样例输入
3
样例输出
text
4
2
4
评测用例规模与约定
对于 30%30% 的数据, N≤10N≤10.
对于 100%100% 的数据, 1<N≤100001<N≤10000.
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
8案例过3个,超时
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 4-修剪灌木-8案例过3-内存太大
* Author:郑龙浩
* Date:2026-04-06
* N 棵树 每天修剪一棵
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
set <vector <int>> set; // 达到过的高度
int n; cin >> n;
vector <int> nums(n, 0);
set.insert(nums);
int pos = 0;
bool direction = true; // 方向
while (true) {
nums[pos] = 0;
// for (int it : nums) cout << it << ' '; cout << '\n';
for (int i = 0; i < n; i++) nums[i] = nums[i] + 1;
// for (int it : nums) cout << it << ' '; cout << '\n' << '\n';
if (set.find(nums) != set.end()) {// 如果循环回来了
// for (int it : nums) cout << it << ' '; cout << '\n';
break;
} else set.insert(nums);
// 确定下一个pos位置
if (direction) {
if (pos == n - 1) {pos = n - 2; direction = false;}
else pos++;
} else {
if (pos == 0) {pos = 1; direction = true;}
else pos--;
}
}
// cout << set.size() << '\n';
vector <vector <int>> new_nums(set.begin(), set.end());
// cout << new_nums.size() << '\n';
for (int j = 0; j < n; j++) {
int Max = 0;
for (int i = 0; i < new_nums.size(); i++) {
Max = max(new_nums[i][j], Max);
}
cout << Max << '\n';
}
return 0;
}
全对
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 4-修剪灌木-8案例过3-修改版-原来是道数学题
* Author:郑龙浩
* Date:2026-04-07修改
* 这是一道数学题,我刚开始以为是个模拟题,就按照最笨的方法存储了多个数组,我其实知道这样会超过内存限制,但是没想到其他的好方法
* 等这次模拟比赛交卷后,我发现自己就对了3个案例,其他全部超过内存限制
* 然后问了AI,我才知道,这TM原来是个数学题,我就没往这方面去想,或者不是数学题,就是稍微转换一下思路就行了,我还以为要什么算法呢,想得太复杂了
* 正确的思考过程是:
* 一个树,最大高度是,将其修剪后为0,然后
* 可能1,向右走:向右遍历到头,然后再回来,经过天数为 2 * (N - i)
* 可能2,向左走:向左遍历到头,然后再回来,经过天数为 2 * (i - 1)
* 天数就是数的高度,因为每天+1
* 所以求出max(2 * (N - i), 2 * (i - 1))即可,保留其中最大的值
*
* 思维还是太固化了,不变通,没有那么灵敏
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
/*
set <vector <int>> set; // 达到过的高度
int n; cin >> n;
vector <int> nums(n, 0);
set.insert(nums);
int pos = 0;
bool direction = true; // 方向
while (true) {
nums[pos] = 0;
// for (int it : nums) cout << it << ' '; cout << '\n';
for (int i = 0; i < n; i++) nums[i] = nums[i] + 1;
// for (int it : nums) cout << it << ' '; cout << '\n' << '\n';
if (set.find(nums) != set.end()) {// 如果循环回来了
// for (int it : nums) cout << it << ' '; cout << '\n';
break;
} else set.insert(nums);
// 确定下一个pos位置
if (direction) {
if (pos == n - 1) {pos = n - 2; direction = false;}
else pos++;
} else {
if (pos == 0) {pos = 1; direction = true;}
else pos--;
}
}
// cout << set.size() << '\n';
vector <vector <int>> new_nums(set.begin(), set.end());
// cout << new_nums.size() << '\n';
for (int j = 0; j < n; j++) {
int Max = 0;
for (int i = 0; i < new_nums.size(); i++) {
Max = max(new_nums[i][j], Max);
}
cout << Max << '\n';
} */
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cout << max(2 * (i - 1), 2 * (n - i)) << endl;
}
return 0;
}
5-X进制减法
不会做,现在会做了
问题描述
进制规定了数字在数位上逢几进一。
XX 进制是一种很神奇的进制, 因为其每一数位的进制并不固定!例如说某 种 XX 进制数, 最低数位为二进制, 第二数位为十进制, 第三数位为八进制, 则 XX 进制数 321 转换为十进制数为 65 。
现在有两个 XX 进制表示的整数 AA 和 BB, 但是其具体每一数位的进制还不确 定, 只知道 AA 和 BB 是同一进制规则, 且每一数位最高为 NN 进制, 最低为二进 制。请你算出 A−BA−B 的结果最小可能是多少。
请注意, 你需要保证 AA 和 BB 在 XX 进制下都是合法的, 即每一数位上的数 字要小于其进制。
输入格式
第一行一个正整数 NN, 含义如题面所述。
第二行一个正整数 MaMa, 表示 XX 进制数 AA 的位数。
第三行 MaMa 个用空格分开的整数, 表示 XX 进制数 AA 按从高位到低位顺序各 个数位上的数字在十进制下的表示。
第四行一个正整数 MbMb, 表示 XX 进制数 BB 的位数。
第五行 MbMb 个用空格分开的整数, 表示 XX 进制数 BB 按从高位到低位顺序各 个数位上的数字在十进制下的表示。
请注意, 输入中的所有数字都是十进制的。
输出格式
输出一行一个整数, 表示 XX 进制数 A−BA−B 的结果的最小可能值转换为十进 制后再模 1000000007 的结果。
样例输入
11
3
10 4 0
3
1 2 0
样例输出
text
94
样例说明
当进制为: 最低位 2 进制, 第二数位 5 进制, 第三数位 11 进制时, 减法 得到的差最小。此时 AA 在十进制下是 108,B108,B 在十进制下是 14 , 差值是 94。
评测用例规模与约定
对于 30%30% 的数据, N≤10;Ma,Mb≤8N≤10;Ma,Mb≤8.
对于 100%100% 的数据, 2≤N≤1000;1≤Ma,Mb≤100000;A≥B2≤N≤1000;1≤Ma,Mb≤100000;A≥B.
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 5-X进制减法-不会做-现在会做了
* Author:郑龙浩
* Date:2026-04-07 会做
* 这道题,我就没读懂题意
* 或者说,我就没看出来「某种 X 进制数, 最低数位为二进制, 第二数位为十进制, 第三数位为八进制, 则 X 进制数 321 转换为十进制数为 65」
* 321是怎么转换为65的,没搞懂这个规则,后面的做法就不用想了,想靠暴力拿部分分都不可能存在了
*
* X进制 -> 十进制 转换规则:
* 例子: X进制的321(从左到右是百位、十位、个位)
* 1:二进制, 2:十进制, 3:百进制
*
* 权重的概念:某位数字假设为1,代表的十进制值是多少
* 个位:权重1
* 十位:权重是「个位的进制」
* 百位:权重是「个位进制 * 十位进制」
*
* 实际计算:
* 数字 十进制
* 个位1:1
* 十位2:2 * (1 * 2) -> (2 * 1 * 2进制)
* 百位3:3 * (2 * 10) -> (3 * 2 * 10进制)
* 相加后为:
* 1 + 2 * (1 * 2) + 3 * (2 * 10) = 65
*
* 知道了进制转换规则后
*
* 还有一个地方要思考,就是该如何确定 A - B 是最小的呢
*
* 当然,需要先将A 和 B转换为十进制后相减,这个相减的值要尽可能的最小
*
* 我刚开始想的是,让每个位都从2~10进制遍历一遍,求出最小的差值来,但是这样一定会超时且内存爆炸
*
* 正确的思路应该是:
* 1 从最低位到最高位,独立确定每位的进制。
* 2 对第 i 位:
1)进制至少要比 A 和 B 在这一位的数字大(因为数字必须小于进制)
2)所以进制最小值 = max(AiJinzhi, Bijinzhi) + 1
3)同时进制 ≥ 2
4)且进制 ≤ N
5)就选这个最小值进制
* 3 这样选的进制保证 A 和 B 合法,且让 A?B 最小。
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 100000 + 5;
const int MOD = 1000000007;
int N, Acnt, Bcnt;
vector <int> A(M, 0), B(M, 0);
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> N >> Acnt;
for (int i = 0; i < Acnt; i++) cin >> A[i];
cin >> Bcnt;
for (int i = 0; i < Bcnt; i++) cin >> B[i];
// 为了数组对齐,需要逆转数组 & 也可以保证如果Acnt和Bcnt长度不同,没有数字的位置是0,此时就不会出错了
// 写错了,因为要求对其,后面的0不要
// reverse(A.begin(), A.end());
// reverse(B.begin(), B.end());
reverse(A.begin(), A.begin() + Acnt);
reverse(B.begin(), B.begin() + Bcnt);
// 处理第i个数字的进制是多少,处理i-1的十进制是多少
ll Anum = 0, Bnum = 0;
ll weight = 1; // 第i位的权重,个位权重肯定是1,所以权重是1,当前位的权重等于前面所有的进制乘积
int len = max(Acnt, Bcnt);
for (int i = 0; i < len; i++) {
int Ai = (i < Acnt) ? A[i] : 0; // Ai是多少,如果大于Acnt就是0
int Bi = (i < Bcnt) ? B[i] : 0;
// 确定当前的进制
int base = max(2, max(Ai, Bi) + 1); // 最少为2进制,所以要保证不出错
if (base > N) base = N; // 最高为N进制(题目限制)
Anum = (Anum + Ai * weight) % MOD;
Bnum = (Bnum + Bi * weight) % MOD;
// 更新权值: 下一位的权值等于当前进制 * 前面的权值
weight = (weight * base) % MOD;
}
// 错误代码:因为可能会出现A - B 为负数的情况(因为数学上模运算是没有负数的)
// cout << (Anum - Bnum) % MOD; 错误写法
// 如果有负数,应该是这样计算的 -2 % 10 = (-2 + 10) % 10 = 8
cout << (Anum - Bnum + MOD) % MOD;
return 0;
}
6-统计子矩阵
问题描述
给定一个 N×MN×M 的矩阵 AA, 请你统计有多少个子矩阵 (最小 1×11×1, 最大 N×M)N×M) 满足子矩阵中所有数的和不超过给定的整数 KK ?
输入格式
第一行包含三个整数 N,MN,M 和 KK.
之后 NN 行每行包含 MM 个整数, 代表矩阵 AA.
输出格式
一个整数代表答案。
样例输入
3 4 10
1 2 3 4
5 6 7 8
9 10 11 12
样例输出
text
19
样例说明
满足条件的子矩阵一共有 19 , 包含:
大小为 1×11×1 的有 10 个。
大小为 1×21×2 的有 3 个。
大小为 1×31×3 的有 2 个。
大小为 1×41×4 的有 1 个。
大小为 2×12×1 的有 3 个。
评测用例规模与约定
对于 30%30% 的数据, N,M≤20N,M≤20.
对于 70%70% 的数据, N,M≤100N,M≤100.
对于 100%100% 的数据, 1≤N,M≤500;0≤Aij≤1000;1≤K≤2500000001≤N,M≤500;0≤Aij≤1000;1≤K≤250000000.
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
10个案例过6个案例
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 6-统计子矩阵-10案例过6个
* Author:郑龙浩
* Date:2026-04-06
* 二维的前缀和
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll nums[30][110] = {0};
int N, M;
ll K;
ll S(int x1, int y1, int x2, int y2) {
if (x1 == 0 && x2 == 0) return nums[x2][y2];
if (x1 == 0) return nums[x2][y2] - nums[x2][y1 - 1];
if (y1 == 0) return nums[x2][y2] - nums[x1 - 1][y2];
return nums[x2][y2] - nums[x1 - 1][y2] - nums[x2][y1 - 1] + nums[x1 - 1][y1 - 1];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> N >> M >> K;
for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) cin >> nums[i][j];
for (int i = 0; i < N - 1; i++) nums[i + 1][0] += nums[i][0];
for (int j = 1; j < M; j++) nums[0][j] += nums[0][j - 1];
for (int i = 1; i < N; i++) for (int j =1; j < M; j++)
nums[i][j] = nums[i - 1][j] + nums[i][j - 1] + nums[i][j] - nums[i - 1][j - 1];
int cnt = 0;
for (int x1 = 0; x1 < N; x1++) for (int y1 = 0; y1 < M; y1++)
for (int x2 = x1; x2 < N; x2++) for (int y2 = y1; y2 < M; y2++) {
// cout << x1 << ' ' << y1 << ' ' << x2 << ' ' << y2 << ' ' << S(x1, y1, x2, y2) << '\n';
if(S(x1, y1, x2, y2) <= K) cnt++;
}
cout << cnt;
return 0;
}
修改后
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 6-统计子矩阵-修改后
* Author:郑龙浩
* Date:2026-04-08
* 二维的前缀和
*/
/*
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll nums[30][110] = {0};
int N, M;
ll K;
ll S(int x1, int y1, int x2, int y2) {
if (x1 == 0 && x2 == 0) return nums[x2][y2];
if (x1 == 0) return nums[x2][y2] - nums[x2][y1 - 1];
if (y1 == 0) return nums[x2][y2] - nums[x1 - 1][y2];
return nums[x2][y2] - nums[x1 - 1][y2] - nums[x2][y1 - 1] + nums[x1 - 1][y1 - 1];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> N >> M >> K;
for (int i = 0; i < N; i++) for (int j = 0; j < M; j++) cin >> nums[i][j];
for (int i = 0; i < N - 1; i++) nums[i + 1][0] += nums[i][0];
for (int j = 1; j < M; j++) nums[0][j] += nums[0][j - 1];
for (int i = 1; i < N; i++) for (int j =1; j < M; j++)
nums[i][j] = nums[i - 1][j] + nums[i][j - 1] + nums[i][j] - nums[i - 1][j - 1];
int cnt = 0;
for (int x1 = 0; x1 < N; x1++) for (int y1 = 0; y1 < M; y1++)
for (int x2 = x1; x2 < N; x2++) for (int y2 = y1; y2 < M; y2++) {
// cout << x1 << ' ' << y1 << ' ' << x2 << ' ' << y2 << ' ' << S(x1, y1, x2, y2) << '\n';
if(S(x1, y1, x2, y2) <= K) cnt++;
}
cout << cnt;
return 0;
}
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// ll nums[30][110] = {0}; // 错误1:数组开小了,看错题目中的数据了
ll colSum[505][505] = {0};
int N, M;
ll K;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> N >> M >> K;
// 从1开始存,方便后续计算前缀和,避免出现越界的情况(也不需要专门判断越界的情况了)
for (int i = 1; i <= N; i++) for (int j = 1; j <= M; j++) cin >> colSum[i][j];
// 只计算列方向的前缀和,方便矩阵压缩
for (int i = 2; i <= N; i++) for (int j = 1; j <= M; j++) {
colSum[i][j] += colSum[i - 1][j];
}
ll cnt = 0; // 存储可以满足条件的矩阵的数量
for (int upper = 1; upper <= N; upper++) {
for (int lower = upper; lower <= N; lower++) {
int left = 1; // 窗口左边界
ll winSum = 0; // 当前窗口之和
for (int right = left; right <= M; right++) { // 窗口右边界
winSum += colSum[lower][right] - colSum[upper - 1][right]; // 将第right列的和加到当前窗口中
while (winSum > K && left <= right) { // 如果当前窗口的和>K,就要将窗口left向右移动
winSum -= colSum[lower][left] - colSum[upper - 1][left];
left++;
}
if (left <= right)
cnt += right - left + 1;
}
}
}
cout << cnt;
return 0;
}
7-积木画
DP题,我放弃了
问题描述
小明最近迷上了积木画, 有这么两种类型的积木, 分别为 II 型(大小为 2 个单位面积) 和 LL 型 (大小为 3 个单位面积):

同时, 小明有一块面积大小为 2×N2×N 的画布, 画布由 2×N2×N 个 1×11×1 区域构 成。小明需要用以上两种积木将画布拼满, 他想知道总共有多少种不同的方式? 积木可以任意旋转, 且画布的方向固定。
输入格式
输入一个整数 NN,表示画布大小。
输出格式
输出一个整数表示答案。由于答案可能很大,所以输出其对 1000000007 取模后的值。
样例输入
3
样例输出
text
5
样例说明
五种情况如下图所示,颜色只是为了标识不同的积木:

评测用例规模与约定
对于所有测试用例,1≤N≤100000001≤N≤10000000.
运行限制
- 最大运行时间:3s
- 最大运行内存: 512M
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 7-积木画
* Author:郑龙浩
* Date:2026-04-06
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int direction[8][2] = {{1, 0}, {0, 1}, {-1, 0}, {-1, -1}, {1, 1}, {0, -1}, {1, -1}, {-1, 1}};
vector <vector <pair <int, int>>> upNext = {
{{0, 0}, {0, 1}},
{{0, 0}, {1, 0}},
{{0, 0}, {0, 1}, {1, 0}},
{{0, 0}, {0, 1}, {1, 1}},
{{0, 0}, {1, 0}, {1, 1}}
};
vector <vector <pair <int, int>>> downNext = {
{{0, 0}, {-1, 0}},
{{0, 0}, {0, 1}},
{{0, 0}, {-1, 0}, {0, 1}},
{{0, 0}, {0, 1}, {-1, 1}},
{{0, 0}, {-1, 0}, {-1, 1}}
};
int grid[2][10000000 + 5] = {0};
int N;
bool check() {
for (int i = 0; i < 2; i++) for (int j = 0; j < N; j++) {
if (grid[i][j] == 0) return false;
}
return true;
}
ll ans = 0;
void dfs(int x, int y) {
if (check()) {
ans++;
return;
}
for (int j = 0; j < N; j++) {
if (grid[0][j] == 1 && grid[1][j] == 1) continue;
if (grid[0][j] == 0) {
for (int next = 0; next < 5; next++) {
vector <pair <int, int>> location;
bool f = true;
for (int x = 0; x < upNext[next].size(); x++) {
int nextX = 0 + upNext[next][x].first;
int nextY = j + upNext[next][x].second;
if (nextX < 0 || nextX >= 2 || nextY < 0 || nextY >= N) {f = false; break;}
if (grid[nextX][nextY] == 1) {f = false; break;}
location.push_back({nextX, nextY});
}
if (f) { // 如果这些位置都能填充,就填上
for (int i = 0; i < location.size(); i++) {
grid[location[i].first][location[i].second] = 1;
// dfs();
grid[location[i].first][location[i].second] = 0; // 回溯
}
}
}
}
if (grid[1][j] == 0) {
for (int next = 0; next < 5; next++) {
vector <pair <int, int>> location;
bool f = true;
for (int x = 0; x < downNext[next].size(); x++) {
int nextX = 0 + downNext[next][x].first;
int nextY = j + downNext[next][x].second;
if (nextX < 0 || nextX >= 2 || nextY < 0 || nextY >= N) {f = false; break;}
if (grid[nextX][nextY] == 1) {f = false; break;}
location.push_back({nextX, nextY});
}
if (f) { // 如果这些位置都能填充,就填上
for (int i = 0; i < location.size(); i++) grid[location[i].first][location[i].second] = 1;
}
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> N;
dfs(0, 0);
dfs(1, 0);
return 0;
}
8-扫雷
全对
题目描述
在一个 nn 行 mm 列的方格图上有一些位置有地雷,另外一些位置为空。
请为每个空位置标一个整数,表示周围八个相邻的方格中有多少个地雷。
输入描述
输入的第一行包含两个整数 n,mn,m。
第 22 行到第 n+1n+1 行每行包含 mm 个整数,相邻整数之间用一个空格分隔。如果对应的整数为 00,表示这一格没有地雷。如果对应的整数为 11,表示这一格有地雷。
其中,1≤n,m≤1001≤n,m≤100 分钟后还是在当天。
输出描述
输出 nn 行,每行 mm 个整数,相邻整数之间用空格分隔。
对于没有地雷的方格,输出这格周围的地雷数量。对于有地雷的方格,输出 99。
输入输出样例
示例 1
输入
txt
3 4
0 1 0 0
1 0 1 0
0 0 1 0
输出
txt
2 9 2 1
9 4 9 2
1 3 9 2
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 8-扫雷
* Author:郑龙浩
* Date:2026-04-06
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool grid[105][105] = {false};
int grid2[105][105] = {0};
int n, m;
int direction[8][2] = {{1, 0}, {0, 1}, {-1, 0}, {-1, -1}, {1, 1}, {0, -1}, {1, -1}, {-1, 1}};
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) cin >> grid[i][j];
for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) {
if (grid[i][j] == true) {grid2[i][j] = 9; continue;}
for (int next = 0; next < 8; next ++) {
int nextX = i + direction[next][0];
int nextY = j + direction[next][1];
if (nextX < 0 || nextX >= n || nextY < 0 || nextY >= m) continue;
if (grid[nextX][nextY] == true) grid2[i][j]++;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m - 1; j++) cout << grid2[i][j] << ' ';
cout << grid2[i][m - 1] << '\n';
}
return 0;
}
9-李白打酒加强版
10案例通过4个-其余超时
问题描述
话说大诗人李白, 一生好饮。幸好他从不开车。
一天, 他提着酒显, 从家里出来, 酒显中有酒 2 斗。他边走边唱:
无事街上走,提显去打酒。 逢店加一倍, 遇花喝一斗。
这一路上, 他一共遇到店 NN 次, 遇到花 MM 次。已知最后一次遇到的是花, 他正好把酒喝光了。
请你计算李白这一路遇到店和花的顺序, 有多少种不同的可能?
注意: 显里没酒 ( 0 斗) 时遇店是合法的, 加倍后还是没酒; 但是没酒时遇 花是不合法的。
输入格式
第一行包含两个整数 NN 和 MM.
输出格式
输出一个整数表示答案。由于答案可能很大,输出模 1000000007 的结果.
样例输入
5 10
样例输出
text
14
样例说明
如果我们用 0 代表遇到花,1 代表遇到店,14 种顺序如下:
010101101000000
010110010010000
011000110010000
100010110010000
011001000110000
100011000110000
100100010110000
010110100000100
011001001000100
100011001000100
100100011000100
011010000010100
100100100010100
101000001010100
评测用例规模与约定
对于 40%40% 的评测用例: 1≤N,M≤101≤N,M≤10 。
对于 100%100% 的评测用例: 1≤N,M≤1001≤N,M≤100 。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
10案例通过4个-其余超时
我用的DFS,实际上这个题应该用DP,但是我已经放弃DP的复习了,不想修改了,跳过吧
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 9-李白打酒加强版
* Author:郑龙浩
* Date:2026-04-06
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m;
ll cnt = 0;
ll sum = 2;
void dfs(bool cur) {
if (n == 0 && m == 0) {
if (sum == 0 && cur == false) cnt++; // 酒喝光了,并且最后一个是花
return;
}
if (sum <= 0) return; /// 如果店或者花还有,但是酒没了,后面就不用看了,不符合,直接return
if (m > 0) {
m--; sum--;
dfs(false);
m++; sum++;
}
if (n > 0) {
n--; sum *= 2;
dfs(true);
n++; sum /= 2;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m;
m--; sum--;
dfs(false);
m++; sum++;
n--; sum *= 2;
dfs(true);
n++; sum /=2;
cout << cnt % 1000000007;
return 0;
}
10-砍竹子
10-砍竹子-拿了5分-运行超时
问题描述
这天, 小明在砍竹子, 他面前有 nn 棵竹子排成一排, 一开始第 ii 棵竹子的 高度为 hihi.
他觉得一棵一棵砍太慢了, 决定使用魔法来砍竹子。魔法可以对连续的一 段相同高度的竹子使用, 假设这一段竹子的高度为 HH, 那么
用一次魔法可以 把这一段竹子的高度都变为 ⌊⌊H2⌋+1⌋⌊⌊2H⌋+1⌋, 其中 ⌊x⌋⌊x⌋ 表示对 xx 向下取整。小明想 知道他最少使用多少次魔法可
让所有的竹子的高度都变为 1 。
输入格式
第一行为一个正整数 nn, 表示竹子的棵数。
第二行共 nn 个空格分开的正整数 hihi, 表示每棵竹子的高度。
输出格式
一个整数表示答案。
样例输入
6
2 1 4 2 6 7
样例输出
text
5
样例说明
其中一种方案:
21426214267→214262→214222→211222→111222→111111→214262→214222→211222→111222→111111共需要 5 步完成
评测用例规模与约定
对于 20%20% 的数据, 保证 n≤1000,hi≤106n≤1000,hi≤106 。 对于 100%100% 的数据, 保证 n≤2×105,hi≤1018n≤2×105,hi≤1018 。
运行限制
- 最大运行时间:2s
- 最大运行内存: 256M
20个案例过了4个-其余案例运行超时
cpp
/* 2026-04-05-06-算法打卡day38-蓝桥杯第13届省赛B组C++
* 10-砍竹子-20个案例过了4个-其余案例运行超时.cpp
* Author:郑龙浩
* Date:2026-04-07
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int N;
const int n = 2 * 1e5 + 5;
ll nums[n];
int MaxIndex() {
int Max = 0;
for (int i = 1; i < N; i++) {
if (nums[Max] < nums[i]) Max = i;
}
return Max;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> N;
for (int i = 0; i < N; i++) cin >> nums[i];
ll cnt = 0;
while (true) {
int maxIndex = MaxIndex(); // 最大数字索引
ll MaxNum = nums[maxIndex];
if (nums[maxIndex] == 1) break;
int right = maxIndex, left = maxIndex - 1;
while (right < N && nums[right] == MaxNum) {
nums[right] = sqrt(nums[right] / 2.0 + 1);
right++;
}
while (left >= 0 && nums[left] == MaxNum) {
nums[left] = sqrt(nums[left] / 2.0 + 1);
left--;
}
cnt++;
if (cnt > n) break;
// cout << maxIndex << ':'; for (int i = 0; i < N; i++) cout << nums[i] << ' '; cout << '\n';
}
cout << cnt;
return 0;
}