2022年蓝桥杯C/C++B组试题及答案,带详细解析,附带提交网站

本文介绍了编程竞赛中遇到的各类问题及解决方案,包括数学、数据结构和图论等算法的应用。通过具体题目分析,展示了如何高效求解复杂度较高的问题,并提供了优化策略和代码实现。同时,文章探讨了动态规划、并查集等重要算法思想,帮助读者提升算法思维能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目提交网站

A

A

答案:1478

B

B

**文字游戏题,答案自取,不多bibi
不算012,答案为4
算012,,答案为14
算倒序(321),答案为15
算倒序(210),答案为47

C

C

思路

先算出一周做题量,可以得出周数,剩下的直接暴力判断就行,水题

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	ll a, b, n;
	cin >> a >> b >> n;
	ll week = a * 5 + b * 2, ans = 0;
	ans += n / week * 7;
	n %= week;
	if(n > 5 * a) {
		ans += 5;
		n -= 5 * a;
		if(n > 0) n -= b, ans += 1;
		if(n > 0) n -= b, ans += 1;
	}
	else {
		ans += (n + a - 1) / a;
	}
	cout << ans << '\n';

	return 0;
}

D

D

思路

不难相出,答案就是当前花的左右距离最大值的二倍。

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n;
	cin >> n;
	vector<int> ans(n + 1);
	for(int i = 1; i <= n; i++) {
		int l = i - 1;
		int r = n - i;
		ans[i] = max(l, r) * 2;
	}
	for(int i = 1; i <= n; i++) cout << ans[i] << '\n';
	return 0;
}

E

E
在这里插入图片描述

思路

没读懂题,后边补上。。。大家读懂的可以给我评论个题意

F

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

思路

我赛场上先是写了发 O ( n 4 ) O(n^4) O(n4)的大暴力,后边写完所有题了再回来优化了一下,最终复杂度为 O ( n 3 ) O(n^3) O(n3)

代码

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

const int maxn = 5e2 + 5;
int a[maxn][maxn];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

	int n, m, k;
	cin >> n >> m >> k;
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
			cin >> a[i][j];
			a[i][j] += a[i - 1][j];
		}
	}
	ll ans = 0;
	for(int i = 1; i <= n; i++) {
		for(int j = i; j <= n; j++) {
			int tmp = 0, l = 1, r = 0;
			while(r <= m && l <= m) {
				while(r + 1 <= m && tmp + a[j][r + 1] - a[i - 1][r + 1] <= k) {
					r++;
					tmp += a[j][r] - a[i - 1][r];
				}
				ans += r - l + 1;
				tmp -= a[j][l] - a[i - 1][l];
				l++;

			}
		}
	}
	cout << ans << '\n';

	return 0;
}

G

在这里插入图片描述
在这里插入图片描述

思路

看到所有题目后最先开的这个题,讲一下我思路

首先引入一个题目,用 1 ∗ 2 1*2 12的骨牌填满 2 ∗ n 2*n 2n的方格,问方案数是多少?
f [ i ] f[i] f[i]为长度为 i i i时的方案数,不难得出 f [ 1 ] = 1 , f [ 2 ] = 2 f[1]=1,f[2]=2 f[1]=1,f[2]=2,那么当 i = 3 i=3 i=3的时候状态转移方程是什么样的呢?

  • 我们考虑结尾是一条竖着的骨牌,并且前 i − 1 i-1 i1长度的状态我们已经得出了,所以有 f [ i ] + = f [ i − 1 ] f[i]+=f[i-1] f[i]+=f[i1]
  • 我们考虑结尾是两个横着的骨牌,并且前 i − 2 i-2 i2长度的状态我们已经得出了,所以有 f [ i ] + = f [ i − 2 ] f[i]+=f[i-2] f[i]+=f[i2]
  • 有同学会问,那结尾还可以是两个竖着的呢?我们仔细想,这个状态真的是我们需要的吗?在第一个状态里,结尾为一个竖着的骨牌,并且在 f [ i − 1 ] f[i-1] f[i1]这个状态里也包含了结尾有一个竖着的骨牌的状态,所以我们不需要结尾是两个竖着的骨牌状态。
  • 所以得出, f [ i ] = f [ i − 1 ] + f [ i − 2 ] f[i] = f[i - 1] + f[i - 2] f[i]=f[i1]+f[i2]

那我们把这种想法带入到本题当中,并且考虑结尾的状态
在这里插入图片描述
经过分析可以得出状态转移方程
f [ 0 ] = 1 , f [ 1 ] = 1 , f [ 2 ] = 2 , i ≤ 2 f[0]=1,f[1] =1,f[2] =2,i{\leq}2 f[0]=1,f[1]=1,f[2]=2,i2
f [ i ] = f [ i − 1 ] + f [ i − 2 ] + 2 ∗ f [ i − 3 ] + . . . . . + 2 ∗ f [ 0 ] , i ≥ 3 f[i] = f[i - 1] + f[i - 2] + 2 * f[i - 3] + .....+2*f[0],i{\geq}3 f[i]=f[i1]+f[i2]+2f[i3]+.....+2f[0],i3
但是复杂度是 O ( n 2 ) O(n^2) O(n2)的,我们考虑优化
对于转移方程的后面部分,共同带有2倍,我们可以用一个变量代替,并且每次循环的时候加上 f [ i − 3 ] f[i-3] f[i3] 的值就行了,复杂度 O ( n ) O(n) O(n)

代码

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

const int mod = 1e9 + 7;

int main() {
	int n;
	cin >> n;
	vector<ll> f(n + 1);
	f[0] = 1, f[1] = 1, f[2] = 2;
	ll pre = 0;
	for(int i = 3; i <= n; i++) {
		f[i] = (f[i - 1] + f[i - 2]) % mod;
		pre = (pre + f[i - 3] * 2) % mod;
		f[i] = (f[i] + pre) % mod;
	}
	cout << f[n] << '\n';
	
	return 0;
}

H

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

  • 注意,给出的爆炸半径都是小于等于10的
  • 一个点处可能有多个炸弹
  • 所以我们设当前点的坐标为 ( x , y ) (x,y) (x,y),我们只需要枚举 ( ( x − 10 , x + 10 ) , ( y − 10 , y + 10 ) ) ((x-10,x+10),(y-10,y+10)) ((x10,x+10),(y10,y+10))这个范围内的点就行了,复杂度由 O ( n 2 ) O(n^2) O(n2)降为 O ( 400 ∗ n ) O(400*n) O(400n),剩下的就是普通BFS了。

代码

#include <bits/stdc++.h>
#define ll long long
#define pii pair<int, int>

using namespace std;

bool cek(pii a, pii b, int r) {
	double dis = 0;
	double x1 = a.first, y1 = a.second;
	double x2 = b.first, y2 = b.second;
	dis = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
	return dis <= r;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	map<pii, int> m1, m2, cnt;
	int n, m;
	cin >> n >> m;
	for(int i = 1; i <= n; i++) {
		int x, y, r;
		cin >> x >> y >> r;
		cnt[pii(x, y)]++;
		m1[pii(x, y)] = max(m1[pii(x, y)], r);
	}
	for(int i = 1; i <= m; i++) {
		int x, y, r;
		cin >> x >> y >> r;
		m2[pii(x, y)] = max(m2[pii(x, y)], r);
	}
	map<pii, int> vis;
	queue<pair<pii, int>> q;
	for(auto it : m2) {
		q.push(it);
		vis[it.first] = 1;
	}
	int ans = 0;
	while(q.size()) {
		pair<pii, int> now = q.front();
		q.pop();
		int x = now.first.first, y = now.first.second, r = now.second;
		for(int i = -10; i <= 10; i++) {
			for(int j = -10; j <= 10; j++) {
				if(i == 0 && j == 0) continue;
				int nx = x + i;
				int ny = y + j;
				if(vis.count(pii(nx, ny)) == 0 && m1.count(pii(nx, ny)) != 0) {
					if(cek(now.first, pii(nx, ny), r)) {
						q.push(pair<pii, int>(pii(nx, ny), m1[pii(nx, ny)]));
						vis[pii(nx, ny)] = 1;
						ans += cnt[pii(nx, ny)];
					}
				}
			}
		}
	}
	cout << ans << '\n';

	return 0;
}

I

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

  • 全分:记忆化搜索/DP
  • 骗部分分:二进制枚举/ 暴力DFS
    d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]代表当前到第 i i i位,遇到了 j j j次店,还剩 k k k斗酒。

代码

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

const int maxn = 205;
const int mod = 1e9 + 7;

ll dp[maxn][maxn][maxn];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

	int n, m;
	cin >> n >> m;
	dp[0][0][2] = 1;
	for(int i = 1; i <= n + m; i++) {
		for(int j = 0; j <= n; j++) {
			for(int k = 1; k <= n + m; k++) {
				if(k % 2 == 0) dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j - 1][k >> 1]) % mod;
				dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k + 1]) % mod;
			}
		}
	}
	int ans = 0;
	cout << dp[n + m - 1][n][1] << '\n';

    return 0;
}

J

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

  • 并查集+优先队列
  • 如果 a [ i ] = a [ i − 1 ] a[i]=a[i-1] a[i]=a[i1],那么合并,并且维护当前集合的祖先是当前集合编号最小的编号
  • 每次取最大的,砍掉,直到结束
#include <bits/stdc++.h>
#define ll long long

using namespace std;

ll gao(ll x) {
	return sqrt(x / 2 + 1);
}

struct DSU {
	int n;
	vector<int> fa, rank;
	DSU(int n_ = 0) : n(n_), fa(n_ + 1), rank(n_ + 1) {
		iota(fa.begin(), fa.end(), 0);
	}

	int find(int x) {
		return x == fa[x] ? x : fa[x] = find(fa[x]);
	}

	void merge(int x, int y) {
		x = find(x), y = find(y);
		if(x == y) return ;
		if(y > x) swap(x, y);
		fa[x] = y;
	}
};

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n;
	cin >> n;
	vector<ll> a(n + 2, -0x3f3f3f3f);
	priority_queue<pair<ll, int>> q;
	DSU dsu(n + 2);
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		q.push(pair<ll, int>(a[i], i));
	}
	for(int i = 2; i <= n; i++) {
		if(a[i] == a[i - 1]) {
			dsu.merge(i, i - 1);
		}
	}
	ll ans = 0;
	while(q.size()) {
		pair<ll, int> now = q.top();
		q.pop();
		ll x = now.first, id = now.second;
		bool ok = 0;
		if(a[id] == 1) continue;
		if(dsu.find(id) != id) continue;
		if(a[dsu.find(id)] == a[dsu.find(id - 1)]) {
			dsu.merge(id, id - 1); 
			continue;
		}
		a[id] = gao(a[id]);
		ans++;
		if(a[dsu.find(id)] == a[dsu.find(id - 1)]) {
			dsu.merge(id, id - 1); 
			continue;
		}
		q.push(pair<ll, int>(a[id], id));
	}
	cout << ans << '\n';
	return 0;
}
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值