【蓝桥杯】第十四届C++B组省赛

发布于:2025-04-02 ⋅ 阅读:(15) ⋅ 点赞:(0)
头像
⭐️个人主页:@小羊
⭐️所属专栏:蓝桥杯
很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~

动图描述


试题A:日期统计

在这里插入图片描述

枚举出2023年所有日期,在数组中查找。结果是:235。

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int ret = 0;
	vector<int> v(100);
	for (int i = 0; i < 100; i++)
	{
		cin >> v[i];
	}
	int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	for (int i = 1; i <= 12; i++)
	{
		for (int j = 1; j <= days[i]; j++)
		{
			string s("2023");
			if (i < 10) s += "0";
			s += to_string(i);
			if (j < 10) s += "0";
			s += to_string(j);
			int k = 0;
			for (int l = 0; l < v.size() && k < 8; l++)
			{
				if ((s[k] - '0') == v[l]) k++;
			} 
			if (k == 8) ret++;
		}
	}
	cout << ret << endl;
	return 0;
}

试题B:01串的熵

在这里插入图片描述

关键是要读懂题目,0的次数比1少,数据范围也不是很大,直接从0出现0次开始枚举,中间过程中某一时刻的值是否等于题目中给定的熵。(特别注意判断浮点数相等,不能用 == 判断,只能判断其差是否在一个范围,通常都用0.1

最后答案是:11027421。

#include <bits/stdc++.h>
using namespace std;

int main()
{
	double len = 23333333;
	double H = 11625907.5798;
	for (int i = 0; i < len / 2; i++)
	{
		double sum = 0;
		sum -= i* (i / len)*log2(i / len) + (len - i)*((len - i) / len)*log2((len - i) / len);
		if (abs(sum - H) < 0.1)
		{
			cout << i << endl;
			break;
		}
	}
	return 0;
} 

试题C:冶炼金属

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

在这里插入图片描述
解题关键:当普通金属的数目不足V时,无法冶炼。
则我们可以得出关系:B * V <= A(B + 1) * V > A,所以 V <= A / BV > A / (B + 1),我们就得到了关于V的一个左右区间,所以 Vr = min(A / B)(右区间的最小值),Vl = max(A / (B + 1) + 1)(左区间的最大值)。

注意细节,为什么 A / (B + 1) 后面还要再加1,因为 V > A / (B + 1) 不能去等号。

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int n;
	cin >> n;
	int vl = INT_MIN, vr = INT_MAX;
	for (int i = 0; i < n; i++)
	{
		int a, b;
		cin >> a >> b;
		vr = min(a / b, vr);
		vl = max(a / (b + 1) + 1, vl);
	}
	cout << vl << " " << vr << endl; 
	return 0;
} 

试题D:飞机降落

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题目数据范围不大,可以考虑暴力枚举尝试正确答案。

  • 每架飞机可以在空中盘旋等待的时间:T[i] + D[i]
  • 即这架飞机可以降落的条件是:T[i] + D[i] >= time,time表示上一架飞机降落后的时刻;
  • 当前飞机降落的过程中,下一架飞机可能在空中盘旋等待,则 time + L[i] 时间后下一架飞机可以开始降落;也可能当前飞机降落了下一架飞机还没来,则 T[i] + L[i]时间后下一架飞机可以开始降落,两种情况下 time 要取较大值。
#include <bits/stdc++.h>
using namespace std;

int t, n;
int T[11], D[11], L[11];
bool used[11] = {}; // 标记是否安排过了当前飞机
int flag = 0; // 标记全部飞机是否安全降落

void dfs(int x, int time) // x表示安排到了第几架飞机,			
{                         // time表示前面一架飞机降落后的时间
	if (x >= n) // 根据题目要求枚举到了最后一架飞机
	{
		flag = 1;
		return;
	}
	for (int i = 0; i < n; i++) // 一架一架的尝试
	{  
		// 当前飞机还没被安排,在天上可以停留的时间>前面飞机降落的最后时间
		if (!used[i] && T[i] + D[i] >= time) 
		{
			used[i] = true; // 如果满足条件就让这个飞机降落
			// 这架飞机降落后下一架飞机可能还没来,或者后面一架飞机在天空盘旋等待
			dfs(x + 1, max(T[i], time) + L[i]);
			used[i] = false;
		}
	}
}
int main()
{
	cin >> t;
	while (t--)
	{
		cin >> n;
		for (int i = 0; i < n; i++)
			cin >> T[i] >> D[i] >> L[i];
		dfs(0, 0); // 第0架飞机在0时刻降落
		if (flag) cout << "YES" << endl;
		else cout << "NO" << endl;
		flag = 0;
	}
	return 0;
}

试题E:接龙数列

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

在这里插入图片描述

题目要求我们求最少删除几个数后剩下的序列是接龙序列,这其实是不好求的,所以我们可以正难则反,求最长接龙序列的长度,转而就得到了最少的删除个数。

定义状态 dp[i] 表示以数字 i 结尾的最长接龙序列的长度。
对于当前数,如果当前数的第一个数字可以接到前面某个数的后面,也就是当前数的第一个数字等于前面某个数的最后一位数,那么当前数就可以接到这个数后面。

状态转移:dp[i] = dp[j] + 1;其中 i 表示当前数的最后一位上的数,j 表示当前数的开头。

#include <bits/stdc++.h>
using namespace std;

int dp[10];

int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		string s;
		cin >> s;
		int sz = s.size();
		dp[s[sz - 1] - '0'] = max(dp[s[sz - 1] - '0'], dp[s[0] - '0'] + 1);
	}
	int ret = 0;
	for (int i = 0; i < 10; i++)
		ret = max(ret, dp[i]);
	cout << (n - ret) << endl;
	return 0;
}

试题F:岛屿个数

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

#include <bits/stdc++.h>
using namespace std;

int m, n;
char arr[51][51];
int dx[8] = {-1, 1, 0, 0, -1, 1, 1, -1};
int dy[8] = {0, 0, -1, 1, 1, 1, -1, -1};
bool used[51][51];

bool check(int i, int j)
{
	for (int i = 0; i <= m; i++)
		for (int j = 0; j <= n; j++)
			used[i][j] = false;
	queue<pair<int, int>> q;
	q.push({i, j});
	used[i][j] = true;
	while (q.size())
	{
		int a = q.front().first, b = q.front().second;
		q.pop();
		for (int k = 0; k < 8; k++)
		{
			int x = a + dx[k], y = b + dy[k];
			if (x < 1 || x > m || y < 1 || y > n) return true;
			if (arr[x][y] == '0' && !used[x][y])
			{
				q.push({x, y});
				used[x][y] = true;
			}
		}
	}
	return false;
}

void dfs(int i, int j)
{
	for (int k = 0; k < 4; k++)
	{
		int x = i + dx[k], y = j + dy[k];
		if (x > 0 && x <= m && y > 0 && y <= n && arr[x][y] == '1')
		{
			arr[x][y] = '0';
			dfs(x, y);	
		} 
	}
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> m >> n;
		for (int i = 1; i <= m; i++)
			for (int j = 1; j <= n; j++)
				cin >> arr[i][j];
		for (int i = 1; i <= m; i++)
			for (int j = 1; j <= n; j++)
				if (arr[i][j] == '1' && !check(i, j))
					arr[i][j] = '0';
		int ret = 0;
		for (int i = 1; i <= m; i++)
			for (int j = 1; j <= n; j++)
				if (arr[i][j] == '1')
				{
					ret++;
					dfs(i, j);
				}
		cout << ret << endl;
	}
	return 0;
}

试题G:子串简写

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

根据样例,从头到尾遍历字符串统计a的个数,在这个过程中只要遇到b就把统计到的a的个数累加到结果中,因为有区间宽度限制,只要在维护的最小宽度也就是k的区间内不累加到结果中就行。

#include<iostream>
using namespace std;

long long ret = 0, cnt = 0;

int main()
{
    int k;
    cin >> k;
    string str;
    char c1, c2;
    cin >> str >> c1 >> c2;
    int l = 0, r = k - 1;
    while (1)
    {
        if (r == str.size()) break;
        if (str[l] == c1) cnt++;
        if (str[r] == c2) ret += cnt;
        l++, r++;
    }
    cout << ret << endl;
    return 0;
}

试题H:整数删除

在这里插入图片描述

在这里插入图片描述

// 样例输入
5 3
1 4 2 8 7
// 样例输出
17 7

直接模拟,只能通过部分测试用例:

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int n, k;
	cin >> n >> k;
	vector<int> v(n);
	for (int i = 0; i < n; i++)
		cin >> v[i];
	while (k--)
	{
		int index = 0;
		for (int i = 0; i < v.size(); i++)
			if (v[index] > v[i])
				index = i;
		if (index - 1 >= 0) v[index - 1] += v[index];
		if (index + 1 < n) v[index + 1] += v[index];
		v.erase(v.begin() + index);
	}
	for (int e : v)
		cout << e << " ";
	return 0;
} 

使用优先级队列+双链表优化时间。

#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using pr = pair<ll, ll>;
const int N = 1e6;
struct { ll prev, next; } a[N]; // 记录对应位置前后的下标,方便删除
ll update[N], ret[N]; // update用于记录每个元素需要更新的值,
 					  // 需要累加的值暂时存到这个数组中
priority_queue<pr, vector<pr>, greater<pr>> pq;

int main()
{
    ll n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        ll x; cin >> x;
        a[i].prev = i - 1;
        a[i].next = i + 1;
        pq.push({x, i});
    }
    while (pq.size() > n - k)
    {
        ll v = pq.top().first, id = pq.top().second;
        pq.pop();
        if (update[id]) // id下标对应的元素有被累加过
        {
            pq.push({v + update[id], id});// 加入小堆中重新选择最小值
            update[id] = 0;
        }
        else
        {
            ll l = a[id].prev, r = a[id].next;
            // 将当前的值加到前后元素上
            update[l] += v;
            update[r] += v;
            // 删除节点
            a[l].next = r;
            a[r].prev = l;
        }
    }
    while (pq.size())
    {
        ll v = pq.top().first, id = pq.top().second;
        pq.pop();
        ret[id] = v + update[id];
    }
    for (auto e : ret)
        if (e) cout << e << " ";
    return 0;
}

试题I:景区导游

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

// 样例输入
6 4
1 2 1
1 3 1
3 4 2
3 5 2
4 6 3
2 6 5 1
// 样例输出
10 7 13 14


试题J:砍树

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

// 样例输入
6 2
1 2
2 3
4 3
2 5
6 5
3 6
4 5
4
// 样例输出
4


本篇文章的分享就到这里了,如果您觉得在本文有所收获,还请留下您的三连支持哦~

头像