2023蓝桥杯省赛c++b组

蓝桥杯真题(更新至2023年) - 编程题库 - C语言网 (dotcpp.com)

A日期统计

小蓝现在有一个长度为 100 的数组,数组中的每个元素的值都在 0 到 9 的范围之内。
数组中的元素从左至右如下所示:

5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2
7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1
0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3

现在他想要从这个数组中寻找一些满足以下条件的子序列:
1. 子序列的长度为 8;
2. 这个子序列可以按照下标顺序组成一个 yyyymmdd 格式的日期,并且
要求这个日期是 2023 年中的某一天的日期,例如 20230902,20231223。
yyyy 表示年份,mm 表示月份,dd 表示天数,当月份或者天数的长度只有一位时需要一个前导零补充。
请你帮小蓝计算下按上述条件一共能找到多少个不同的 2023 年的日期。
对于相同的日期你只需要统计一次即可。 
本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<map>
#include<algorithm>
#define maxn 200
#define lli long long int
using namespace std;
lli  a[101];
map<int, int>mp;

int check(int data)//这个函数感觉不用讲
{
	if (mp[data] == 1)//判重
		return 0;
	mp[data] = 1;
	int y = data / 10000;
	int m = data / 100 % 100;
	int d = data % 100;
	if (m <= 0 || m > 12)
		return 0;
	if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12)
	{
		if (d > 31 || d == 0)
			return 0;

	}
	else if (m == 2)
	{
		if (d > 28 || d == 0)
			return 0;
	}
	else
	{
		if (d > 30 || d == 0)
			return 0;
	}
	return 1;

}
int ans = 0;
int nnn[1000];
int cnt = 0;
void  dfs(int data, int num, int pos)
{
	if (num == 100)
		return;
	if (pos == 8)
	{
		if (check(data))
		{
			ans++;
			//nnn[++cnt] = data;
		}

		return;
	}
	if (pos == 0 && a[num] == 2 ||
		pos == 1 && a[num] == 0 ||
		pos == 2 && a[num] == 2 ||
		pos == 3 && a[num] == 3 ||
		pos == 4 && a[num] <= 1 && a[num] >= 0 ||
		pos == 5 && a[num] >= 0 && a[num] <= 9 ||
		pos == 6 && a[num] >= 0 && a[num] <= 3 ||
		pos == 7 && a[num] >= 0 && a[num] <= 9
		)//这里粗略判断,check仔细判断
         //如果符合这个条件,就可以在这个基础从后面找下一位
		dfs(data * 10 + a[num], num + 1, pos + 1);
	dfs(data, num + 1, pos);//这个a[num]不能当pos位置的数字,就无视他看他下一个行不行。
}
void solve()
{
	int n, m;
	for (int i = 0; i < 100; i++)
		cin >> a[i];
	dfs(0, 0, 0);

	cout << ans;
	/*sort(nnn + 1, nnn + 1 + cnt);
	for (int i = 1; i <= ans; i++)
		cout << nnn[i] << '\n';*/
//这里是我看看所有日期是不是都符合条件
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	int t = 1;
	//cin >> t;
	while (t--)
		solve();



}

B 01熵

对于一个长度为 n 的 01 串 S = x1x2x3...xn.
香农信息熵的定义为:
 


其中 p(0), p(1) 表示在这个 01 串中 0 和 1 出现的占比。
比如,对于S = 100 来说,信息熵 H(S ) = - 1/3 log2(1/3) - 2/3 log2(2/3) - 2/3 log2(2/3) = 1.3083。
对于一个长度为23333333 的 01 串,如果其信息熵为 11625907.5798,且 0 出现次数比 1 少,那么这个01 串中 0 出现了多少次?
本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

思路:这个照着题意敲就行,纯暴力。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cmath>
#include<map>
#include<algorithm>
#define maxn 200
#define lli long long int
using namespace std;
lli  a[101];
map<int, int>mp;
void solve()
{
	double n= 23333333;
	double h= 11625907.5798;
	for (int i = 1; i < n / 2; i++)
	{
		double ans = -1.0*i* (i / n) * log2(i / n) - 1.0*(n-i)*((n - i) / n) * log2((n - i) / n);
		if (ans > 11625907.57&&ans< 11625907.58)
		{
			cout << i;
			return ;
		}
	}

}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	int t = 1;
	//cin >> t;
	while (t--)
		solve();



}

C冶炼金属

思路:这题我写了几个数,发现就是取一堆数据的最小值的最大值,和最大值的最小值(人话:公共部分)。看样例的解释,凑出的通式。

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<map>
#include<stack>
#include<set>
#include<queue>

#define maxn 500010
//#define ll long long
#define int long long

int n;
int a, b;
int minn = 0, maxx = 0x3f3f3f3f3f;
int x, y;
using namespace std;

void solve()
{

	cin >> n;

	for (int i = 1; i <= n; i++) {
		cin >> a >> b;
		x = a * 1.0 / (b + 1)+1;
		y = a * 1.0 / b;
		minn = max(x, minn);
		maxx = min(y, maxx);
	}
	cout <<minn<<" "<< maxx;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	//int t;
	//cin >> t;
	//while(t--)
	solve();
	return 0;
}

 二分:

#include<iostream>
#define maxn 100010
using namespace std;
int a[maxn], b[maxn];
int t;
int c1(int x)
{
	for (int i = 1; i <= t; i++)
		if (a[i] / x > b[i])//超出了最小值
			return 0;
	return 1;
}
int c2(int x)
{
	for (int i = 1; i <= t; i++)
		if (a[i] / x < b[i])//取大了
			return 0;
	return 1;
}
int main()
{
	int maxx=0, minn = 1e9 + 10;
	cin >> t;
	int l = 1, r = t,mid=0;
	for (int i = 1; i <= t; i++)
	{
		cin >> a[i] >> b[i];
		r = max(r, a[i]);
	}
	int mm = r;
	while (l <= r)
	{
		mid = (l + r) / 2;
		if (c1(mid))
			r= mid-1;
		else//x取小了,应该往大了取
			l = mid+1;
	}
	minn = l;
	l = 1, r = mm, mid = 0;
	while (l <= r)
	{
		mid = (l + r) / 2;
		if (c2(mid))
			l = mid + 1;
		else//x取大了,应该往小了取
			r = mid-1;
	}
	maxx =l;
	cout << minn << ' ' << maxx;
}

D飞机降落

思路:看注释即可

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<map>
#include<stack>
#include<set>
#include<queue>

#define maxn 20
#define ll long long
#define int long long

int n, t[maxn], d[maxn], l[maxn],flag,f[maxn];
//n:飞机数;
//t[]:到达时间
//d[]:盘旋时间
//l[]:落地所需时间
//flag:是否能全都塞下
//f[]:是否来过这个
using namespace std;
void dfs(int x,int tim)
{
	if (flag )
		return;
	if (x == n)
	{
		flag = 1;
		return;
	}
	for (int i = 1; i <= n; i++)
	{
		//暴力深搜,只要当前时间小于当前飞机最晚降落时间就进入判断
		if (f[i] == 0 && tim <= t[i] + d[i])
		{
		    f[i] = 1;//来过
			//dfs(已经安排下的飞机的个数,此飞机到地面的时间)
			dfs(x + 1, max(t[i], tim) + l[i]);
			//t[i]是到达时间,tim则是当前时间可能会让飞机盘旋一会儿
			if (flag)
				return;
			f[i] = 0;//防止影响其他路径的标记
		}
	}
}
void solve()
{
	memset(t, 0, sizeof(t));
	memset(d, 0, sizeof(d));
	memset(l, 0, sizeof(l));
	memset(f, 0, sizeof(f));
	flag = 0;
	cin >> n;
	for(int i=1;i<=n;i++)
		cin >> t[i] >> d[i] >> l[i];
	dfs(0, 0);
	if (flag)
		cout << "YES" << endl;
	else
		cout << "NO" << endl;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
	return 0;
}

E: 接龙数列

思路:在注释里

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<map>
#include<stack>
#include<set>
#include<queue>

#define maxn 20
#define ll long long
#define int long long

int dp[10];
//也就10种可能结尾0~9
//dp[i]为以i为结尾的最长长度。
using namespace std;

void solve()
{
	int n;
	cin >> n;
	string x;
	for (int i = 1; i <= n; i++)
	{
		cin >> x;
		int a = x[0] - '0', b = x.back() - '0';
		//dp[b]是以b结尾当前最长的接龙序列,
		//当前要最长,就要把上一个以a为结尾的序列加上本个的长度,和以b为结尾的序列比较。
	
		dp[b] = max(dp[b], dp[a] + 1);
	}
	int maxx=0;
//看看哪个结尾的序列最长
	for (int i = 0; i < 10; i++)
	{
		maxx = max(dp[i], maxx);
	}
	cout << n-maxx << endl;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	/*int t;
	cin >> t;
	while(t--)*/
	solve();
	return 0;
}

F 岛屿个数

思路:一开始我想错了,把子岛也求了。这题两遍搜索就能做,我习惯深搜。第一遍把岛屿外面的0全改成2(8方搜索),然后把里面的0改成1,第二for循环搜索遍历岛屿(四方搜索),看看有几个。

为什么第一遍8方,第二遍四方呢。首先我们要知道只有有公共边才算同一个岛屿,举个例子:

0 2 1 0                           0 1 1 0

0 1 3 0                           0 1 0 0

   图一                                  图二

假设一下,岛屿外是海,岛屿内是河。图中是有两个岛的,图1的3点是海,2点也是,2点8方可以搜到3,他们也算是联通的;同理,图二只有一个岛。


#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<map>
#include<stack>
#include<set>
#include<queue>

#define maxn 20
#define ll long long
//#define int long long


int n, m;
int k = 0;
char g[55][55];
int d4[4][2] = { {0,1},{0,-1},{-1,0},{1,0} };
int d8[8][2] = { {0,1},{0,-1},{-1,0},{1,0},{-1,1},{-1,-1},{1,-1},{1,1} };
//可以深搜一条路径,每一步+1(即求长度),但是注意要从2开始,最后看有几个2
//也可以一条路径都是一个数,看看图中最大数是几

using namespace std;

void  dfs1(int x, int y)
{
	g[x][y] = '2';
	for (int p = 0; p < 8; p++)
	{
		int dx = x + d8[p][0], dy = y + d8[p][1];
		if (dx >= 0 && dx <= m+1 && dy >= 0 && dy <= n+1 && g[dx][dy] == '0')//
			dfs1(dx, dy);
	}
	return;
}
void  dfs2(int x, int y)
{
	g[x][y] = '0';//这里只要不是1就行,随便改
	for (int p = 0; p < 4; p++)
	{
		int dx = x + d4[p][0], dy = y + d4[p][1];
		if (dx >= 1 && dx <= m && dy >= 1 && dy <= n && g[dx][dy] == '1')
			dfs2(dx, dy);
	}
	return;
}
void solve()
{
	k = 0;
	memset(g,'0', sizeof(g));
	cin >> m>>n;
	for(int i=1;i<=m;i++)
		for (int j = 1; j <= n; j++)
			cin >> g[i][j];
	dfs1(0,0);
	for (int i = 0; i <= m+1; i++)
		for (int j = 0; j <= n+1; j++)//这里是为了保证所有岛屿外面有水,并且通过dfs让水2灌满所有没岛的地方
			if (g[i][j] == '0')
				g[i][j] = '1';
	//cout << endl;
	//for (int i = 0; i <= m+1; i++)
	//{
	//	for (int j = 0; j <= n+1; j++)
	//		cout << g[i][j];
	//	cout << endl;
	//}
	for(int i=0;i<=m+1;i++)
		for (int j = 0; j <= n+1; j++)
		{
			if (g[i][j] == '1')
			{
				dfs2(i,j);
				k++;
			}
		}
		//cout << endl;
	cout << k << endl;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
	return 0;
}

 G子串个数

思路:找到所有头l和尾r出现的位置,然后存起来。利用r[j] >= l[i] + k - 1这一关系,找出每一个头的总数,加和即可。

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<map>
#include<stack>
#include<set>
#include<queue>

#define maxn 500010
//#define ll long long
#define int long long



using namespace std;

void solve()
{
	int k;
	cin >> k;
	string s;
	char a, b;
	cin >> s>>a>>b;
	//cout << s <<endl<<a <<endl<< b;
	int n = s.size();
	int l[maxn], r[maxn];
	int ll = 0, rr = 0;
	for (int i = 0; i < n; i++)
	{
		if (s[i] == a)
			l[++ll] = i;//开头的下标
		if (s[i] == b)
			r[++rr] = i;//结尾的下标
	}
	//以每一个开头的下标为基,看看右边几个比他大的
	int ans = 0;
	//for (int i = 1; i <= ll; i++)
	//{
	//	for (int j = rr; j >= 1; j--)
	//		if (r[j] < l[i]+k-1)//第j个右点小于基点,也就是从这开始不能形成字符串
	//		{
	//			ans += rr - j;//减去即可
	//			break;
	//		}
	//}
	//上述暴力仅能95分,我们再优化一下。我们可以注意到前面很多点其实是无效重复跑的。
	//比如说ababb,k=2.第一个b肯定是无效的,但是我们还在跑;第二个b生效一次之后,
	//只有后面的b有效,所以我们可以找个数存一下,以后查询直接跳过去。
	int temp = 1;
	for (int i = 1; i <= ll; i++)
	{
		for (int j = temp; j <= rr; j++)
		{
			//倒着跑是找第一个小于的,正着跑是找第一个大于的再-1。
			if (r[j] >= l[i] + k - 1)//第j个右点小于基点,也就是从这开始不能形成字符串
			{
				temp = j;
				ans += rr - j+1;//减去即可
				//这里的+1大家可能没明白,就比如说第j个开始就符合条件,那我们就用"总数-(j-1)"对吧,也就是这里的-j+1
				break;
			}
		}
	}
	cout << ans;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	//int t;
	//cin >> t;
	//while(t--)
	solve();
	return 0;
}

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值