<>第十二届蓝桥杯C++B 组真题

<>试题A. 空间

1MB= 1024KB 1KB= 1024B 1B= 1b
#include <iostream> using namespace std; int main() { cout << 256 * 1024 *
1024 / 4; return 0; }
<>试题B 卡片

#include <iostream> using namespace std; int a[11]; bool check(int n) {
while(n) { int t = n % 10; if(-- a[t] < 0) return true; n /= 10; } return
false; } int main() { for(int i = 0; i < 10; i ++) a[i] = 2021; for(int i = 1;
; i ++) { if(check(i)) { cout << i - 1; return 0; } } }
<>试题C 直线

set判重写法
#include<iostream> #include<set> #include<vector> #include<cmath> using
namespace std; typedef pair<int,int> PII; set<pair<PII, int>> s; //约分后去重
vector<PII> v; int gcd(int a, int b) //最大公约数进行约分 { return b ? gcd(b, a % b) :
a; } int main(){ for(int i = 0; i < 20; i++) for(int j = 0; j < 21; j++ )
v.push_back({i,j}); //读入所有点 for(int i = 0; i < v.size(); i++) { for(int j = i +
1; j < v.size(); j++) { int x1 = v[i].first, y1 = v[i].second; int x2 =
v[j].first, y2 = v[j].second; int A = x2 - x1, B = y1 - y2, C = x1 * y2 - x2 *
y1; int d = gcd(gcd(A,B), C); s.insert({ { B / d, A / d }, C / d });
//读入约分后的斜率和常数set自动判重 } } cout << s.size(); return 0; }

#include <iostream> #include <cstring> #include <algorithm> #include <cmath>
using namespace std; const int N = 200000; int n; struct Line { double k, b;
bool operator< (const Line& t) const { if (k != t.k) return k < t.k; return b <
t.b; } }l[N]; int main() { for (int x1 = 0; x1 < 20; x1 ++ ) for (int y1 = 0;
y1 < 21; y1 ++ ) for (int x2 = 0; x2 < 20; x2 ++ ) for (int y2 = 0; y2 < 21; y2
++ ) if (x1 != x2) { double k = (double)(y2 - y1) / (x2 - x1); double b = y1 -
k * x1; l[n ++ ] = {k, b}; } sort(l, l + n); int res = 1; for (int i = 1; i <
n; i ++ ) if (fabs(l[i].k - l[i - 1].k) > 1e-8 || fabs(l[i].b - l[i - 1].b) >
1e-8) res ++ ; cout << res + 20 << endl; //加上斜率为0的二十个竖线 return 0; }
<>试题D 货物摆放

#include <iostream> #include <cstring> #include <algorithm> #include <vector>
using namespace std; typedef long long LL; int main() { LL n =
2021041820210418; vector<LL> d; //约数板子 for (LL i = 1; i * i <= n; i ++ ) if (n
% i == 0) { d.push_back(i); if (n / i != i) d.push_back(n / i); } int res = 0;
for (auto a: d) for (auto b: d) for (auto c: d) if (a * b * c == n) res ++ ;
cout << res << endl; return 0; }
<>试题E 路径

#include <iostream> #include <cstring> #include <algorithm> #include <queue>
using namespace std; const int N = 2200, M = N * 50; int n; int h[N], e[M],
w[M], ne[M], idx; int q[N], dist[N]; bool st[N]; int gcd(int a, int b) //

spfa() { memset(dist, 0x3f, sizeof dist); dist[1] = 0; queue<int> q; q.push(1);
st[1] = true; while (q.size()) { int t = q.front(); q.pop(); st[t] = false; for
(int i = h[t]; i != -1; i = ne[i]) { int j = e[i]; if (dist[j] > dist[t] +
w[i]) { dist[j] = dist[t] + w[i]; if (!st[j]) { q.push(j); st[j] = true; } } }
} return dist[n]; } int main() { n = 2021; memset(h, -1, sizeof h); for (int i
= 1; i <= n; i ++ ) for (int j = max(1, i - 21); j <= min(n, i + 21); j ++ ) {
int d = gcd(i, j); add(i, j, i * j / d); } printf("%d\n", spfa()); return 0; }
<>试题F 时间显示

#include <iostream> #include <cstring> #include <algorithm> using namespace
std; typedef long long LL; int main() { LL n; cin >> n; n /= 1000; n %= 86400;
int h = n / 3600; n %= 3600; int m = n / 60; int s = n % 60;
printf("%02d:%02d:%02d\n", h, m, s); return 0; }
<>试题G 砝码称重

<>题目描述

<>输入格式

<>输出格式

<>输入样例
3 1 4 6
<>输出样例
10

#include <iostream> #include <cstring> #include <algorithm> using namespace
std; const int N = 110, M = 200010, B = M / 2; int n, m; int w[N]; bool
f[N][M]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++ )
scanf("%d", &w[i]), m += w[i]; f[0][B] = true; for (int i = 1; i <= n; i ++ )
for (int j = -m; j <= m; j ++ ) //负数就是放左面， 正数就是右面 { f[i][j + B] = f[i - 1][j +
B]; //有可能出现负数的情况，所以要在所有二维中加入偏移量 if (j - w[i] >= -m) f[i][j + B] |= f[i - 1][j -
w[i] + B];//有相等情况或等于 if (j + w[i] <= m) f[i][j + B] |= f[i - 1][j + w[i] + B];
//同f[i][j + B] = f[i - 1][j + w[i] + B] || f[i][j + B]; } int res = 0; for (int
j = 1; j <= m; j ++ ) if (f[n][j + B]) res ++ ; printf("%d\n", res); return 0; }
<>试题 H 杨辉三角形

<>题目描述

1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, …

<>输入格式

<>输出格式

<>输入样例
2 3 6
<>输出样例
8 13

#include <iostream> #include <cstring> #include <algorithm> using namespace
std; typedef long long LL; int n; /* 找第一个，而杨辉三角是对称的所以不可能在右面 1 --- C(0, 0) 1 1 2
--- C(2, 1) 1 3 1 4 6 --- C(4, 2) 1 5 10 1 6 15 20 --- C(6, 3) ....

//直接暴力求组合数 { LL res = 1; for (int i = a, j = 1; j <= b; i --, j ++ ) { res =
res * i / j; if (res > n) return res; } return res; } bool check(int k) //二分求值
{ LL l = k * 2, r = max((LL)n, l); // 第一行特殊情况， r必须比l大 while (l < r) { LL mid =
l + r >> 1; if (C(mid, k) >= n) r = mid; else l = mid + 1; } if (C(r, k) != n)
return false; //根据坐标（r,k）求出位置 cout << r * (r + 1) / 2 + k + 1 << endl; return
true; } int main() { cin >> n; // n最大1e9，C(34, 17) > 1e9, C(32, 16) <
1e9，因此只要枚举前16个斜行即可 for (int k = 16; ; k -- ) if (check(k)) break; return 0; }
<>试题I 双向排序

<>题目描述

<>输入格式

<>输出格式

<>输入样例
3 3 0 3 1 2 0 2
<>输出样例
3 1 2

* 原序列 AA 段严格大于 BB 段
* AA 段 == A1A1 段， BB 段 == B1B1 段
* 所以 A1A1 段严格大于 B1B1 段
* A2A2 段 == A1A1 段
* 所以 A2A2 段严格大于 CC 段，所以后缀升序操作（橙色）只需要操作 CC 段即可
*

#include <iostream> #include <cstring> #include <algorithm> #define x first
#define y second using namespace std; typedef pair<int, int> PII; const int N =
100010; int n, m; PII stk[N]; int ans[N]; int main() { scanf("%d%d", &n, &m);
int top = 0; while (m -- ) { int p, q; scanf("%d%d", &p, &q); if (!p) { while
(top && stk[top].x == 0) q = max(q, stk[top -- ].y); while (top >= 2 && stk[top
- 1].y <= q) top -= 2; stk[ ++ top] = {0, q}; } else if (top) { while (top &&
stk[top].x == 1) q = min(q, stk[top -- ].y); while (top >= 2 && stk[top - 1].y
>= q) top -= 2; stk[ ++ top] = {1, q}; } } int k = n, l = 1, r = n; for (int i
= 1; i <= top; i ++ ) { if (stk[i].x == 0) while (r > stk[i].y && l <= r) ans[r
-- ] = k -- ; else while (l < stk[i].y && l <= r) ans[l ++ ] = k -- ; if (l >
r) break; } if (top % 2) while (l <= r) ans[l ++ ] = k -- ; else while (l <= r)
ans[r -- ] = k -- ; for (int i = 1; i <= n; i ++ ) printf("%d ", ans[i]);
return 0; }
<>试题J 括号序列

<>题目描述

<>输入格式

<>输出格式

<>输入样例
((()
<>输出样例
5

#include <iostream> #include <cstring> #include <algorithm> using namespace
std; typedef long long LL; const int N = 5010, MOD = 1e9 + 7; int n; char
str[N]; LL f[N][N]; //前i个括号左括号比右括号多j个的集合 LL work() { //初始化 memset(f, 0, sizeof
f); f[0][0] = 1; for (int i = 1; i <= n; i ++ ) if (str[i] ==
'(')//如果是左括号就是之前状态的j - 1 { for (int j = 1; j <= n; j ++ ) f[i][j] = f[i - 1][j
- 1]; } else { f[i][0] = (f[i - 1][0] + f[i - 1][1]) % MOD; for (int j = 1; j
<= n; j ++ ) /* f[i][j] = f[i - 1][0] + f[i - 1][1] + ...... + f[i - 1][j]
f[i][j + 1] = f[i - 1][0] + f[i - 1][1] + ...... + f[i - 1][j] + f[i - 1][j +
1] 那么我们可以得出 f[i][j] = f[i][j - 1] + f[i - 1][j - 1] */ f[i][j] = (f[i - 1][j +
1] + f[i][j - 1]) % MOD; } for (int i = 0; i <= n; i ++ ) if (f[n][i]) return
f[n][i]; return -1; } int main() { scanf("%s", str + 1); n = strlen(str + 1);
LL l = work(); //由于状态转移是用左括号表示的， 而题目是右括号所以只需反转左右括号对调一下就可以了 reverse(str + 1, str
+ n + 1); for (int i = 1; i <= n; i ++ ) if (str[i] == '(') str[i] = ')'; else
str[i] = '('; LL r = work(); printf("%lld\n", l * r % MOD); return 0; }
<>参考：

acwing 《蓝桥杯C++AB组辅导课》

GitHub

Gitee