【比赛】第十四届蓝桥杯大赛软件赛决赛 C/C++ 大学 B 组(比赛过程记录,不是答案总结,待更新,文末查询蓝桥杯相关信息)

试题 A: 子 2023

本题总分:5 分
【问题描述】
小蓝在黑板上连续写下从 1 到 2023 之间所有的整数,得到了一个数字序列:
S = 12345678910111213 . . . 20222023。
小蓝想知道 S 中有多少种子序列恰好等于 2023?
提示,以下是 3 种满足条件的子序列(用中括号标识出的数字是子序列包含的数字):
1[2]34567891[0]111[2]1[3]14151617181920212223…
1[2]34567891[0]111[2]131415161718192021222[3]…
1[2]34567891[0]111213141516171819[2]021222[3]…
注意以下是不满足条件的子序列,虽然包含了 2、0、2、3 四个数字,但是顺序不对:
1[2]345678910111[2]131415161718192[0]21222[3]…

思路

这一道题目的数字量有一点大,但是其实最终的答案只是和数字“2”“3”“0”有关,我们可以先将这些数字提取出来,单纯提取出来数字2、3、0之后差不多有2000个左右,然后我们通过对数字“2023”进行观察可以发现,2这个数字出现的次数比较多,那我们考虑0和3来突破,来看下面的例子:
输入数字:2020233 输出:8
这道题我是把每一个3作为一个计算的点,这个例子就有两个3,我们先考虑第一个3,此时输入一个输入的内容可以理解为:202023,然后我们再来观察我们需要求的目标值2023,这个时候我们可以发现3前面有两个0,这两个0我们又可以分开来计算,对于每一个0来说他对应的个数就是左边2的个数乘以右边2的个数。所以我们最终就是要遍历3和0的位置就好,2的个数可以预处理。

代码

#include <iostream>
#include <vector>
#define debug(x) cout<<#x<<" = "<<x<<endl
using namespace std;
typedef long long LL;

const int N = 1e5;
vector<int> arr;
void shu(int x)
{
	if(x==2||x==3||x==0)arr.push_back(x);
}

int main() 
{
	
	for(int i=1;i<=2023;++i)
	{
		if(i>=1000)shu(i/1000);
		if(i>=100)shu((i/100)%10);
		if(i>=10)shu((i/10)%10);
		if(i>=1)shu(i%10);
	}
	
	
	int a2[2000];
	int zhi2=0,zhi0=0,zhi3=0;
	int geshu2=0;
	long long ans=0;
	for(int i=0;i<arr.size();++i)
	{
		if(arr[i]==2)geshu2++;
		a2[i]=geshu2;
	}
	for(int i=0;i<arr.size();++i)
	{
		if(arr[i]==3)
			for(int j=0;j<i;++j)
			{
				if(arr[j]==0)ans+=(a2[j]*(a2[i]-a2[j]));//cout<<a2[j]*(a2[i]-a2[j])<<endl;
				
			}
	}
	cout<<ans;
	return 0;
}

试题 B: 双子数

本题总分:5 分
【问题描述】
若一个正整数 x 可以被表示为 p2 × q2,其中 p、q 为质数且 p , q,则 ppq*q 是一个 “双子数”。请计算区间 [2333, 23333333333333] 内有多少个 “双子数”?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

思路

经过计算我们可以发现右边界开平方之后就等于4830458,也就是说在这个范围之内找两个质数相乘在题目区间之间,求个数。

代码

#include <bits/stdc++.h>
#include <vector>
#define  debug(x) cout<<#x<<" = "<<x<<endl
using namespace std;
typedef long long LL;

const int N = 1e7;
int prime[N]{0};
bool st[(int)1e8]{0};
int cnt=0;

void get_prime(int x)
{
	for(int i=2;i<=x;++i)
	{
		if(!st[i])
		{
			prime[cnt++]=i;
			for(int j=2;j*i<=x;++j)
				st[i*j]=1;
				//cout<<i<<endl;
		}
	}
}

int main() 
{
	int n=4830458;
	//n=100;
	get_prime(n);
	LL ans=0;
	for(int i=0;i<cnt;++i)
		for(int j=i+1;j<cnt;++j)
			if((LL)prime[i]*(LL)prime[j]<=(LL)n&&(LL)prime[i]*(LL)prime[j]>=(LL)2333)ans++;//cout<<prime[i]<<" "<<prime[j]<<endl;
			else if((LL)prime[i]*(LL)prime[j]>n)break;
	cout<<ans;
	return 0;
}

试题 C: 班级活动

时间限制: 1.0s 内存限制: 256.0MB 本题总分:10 分
【问题描述】
小明的老师准备组织一次班级活动。班上一共有 n 名(n 为偶数)同学,
老师想把所有的同学进行分组,每两名同学一组。为了公平,老师给每名同学
随机分配了一个 n 以内的正整数作为 id,第 i 名同学的 id 为 ai。
老师希望通过更改若干名同学的 id 使得对于任意一名同学 i,有且仅有另
一名同学 j 的 id 与其相同(ai = aj)。请问老师最少需要更改多少名同学的 id?
【输入格式】
输入共 2 行。
第一行为一个正整数 n。
第二行为 n 个由空格隔开的整数 a1, a2, …, an。
【输出格式】
输出共 1 行,一个整数。
【样例输入】
4
1 2 2 3
【样例输出】
1
【样例说明】
仅需要把 a1 改为 3 或者把 a3 改为 1 即可。

思路

每一个数字都记录下他们的个数,把偶数个的忽略,求奇数个的有多少种,结果除以二就好。

代码

#include <bits/stdc++.h>
#include <vector>
#define  debug(x) cout<<#x<<" = "<<x<<endl
using namespace std;
typedef long long LL;

int main() 
{
	int n;
	cin>>n;
	vector<LL> arr;
	for(int i=0;i<n;++i)
	{
		LL shuru;
		scanf("%lld",&shuru);
		arr.push_back(shuru);
	}
	sort(arr.begin(),arr.end());
	//for(int i=0;i<n;++i)cout<<arr[i]<<" ";cout<<endl;
	int sum=0;
	int geshu=1;
	for(int i=1;i<n;++i)
	{
		if(arr[i]!=arr[i-1])
		{
			if(geshu&1)sum++;
			geshu=1;
		}
		else geshu++;
		//debug(geshu);
	}
	if(geshu&1)sum++;
	cout<<sum/2;
	return 0;
}

试题 D: 合并数列

时间限制: 1.0s 内存限制: 256.0MB 本题总分:10 分
【问题描述】
小明发现有很多方案可以把一个很大的正整数拆成若干正整数的和。他采
取了其中两种方案,分别将他们列为两个数组 {a1, a2, …, an} 和 {b1, b2, …, bm}。两
个数组的和相同。
定义一次合并操作可以将某数组内相邻的两个数合并为一个新数,新数的
值是原来两个数的和。小明想通过若干次合并操作将两个数组变成一模一样,
即 n = m 且对于任意下标 i 满足 ai = bi。请计算至少需要多少次合并操作可以
完成小明的目标。
【输入格式】
输入共 3 行。
第一行为两个正整数 n, m。
第二行为 n 个由空格隔开的整数 a1, a2, …, an。
第三行为 m 个由空格隔开的整数 b1, b2, …, bm。
【输出格式】
输出共 1 行,一个整数。
【样例输入】
4 3
1 2 3 4
1 5 4
【样例输出】
1
【样例说明】
只需要将 a2 和 a3 合并,数组 a 变为 {1, 5, 4},即和 b 相同。
【评测用例规模与约定】
对于 20% 的数据,保证 n, m ≤ 103。
对于 100% 的数据,保证 n, m ≤ 105,0 < ai, bi ≤ 105。

思路

最终都是一样的序列,那么就从左边往右边两个指针遍历,遇到不一样的情况较小值往后面加,记录次数。

代码

#include <bits/stdc++.h>
#include <vector>
#define  debug(x) cout<<#x<<" = "<<x<<endl
using namespace std;
typedef long long LL;

int main() 
{
	int n,m;
	cin>>n>>m;
	vector<int>a;
	vector<int>b;
	vector<int>a_next;
	vector<int>b_next;
	for(int i=0;i<n;++i)
	{
		int shuru;
		scanf("%d",&shuru);
		a.push_back(shuru);	
		a_next.push_back(i+1);
	}
	for(int i=0;i<m;++i)
	{
		int shuru;
		scanf("%d",&shuru);
		b.push_back(shuru);
		b_next.push_back(i+1);
	}
	int zhizhen1=0;
	int zhizhen2=0;
	int ans=0;
	while(zhizhen1<n&&zhizhen2<m)
	{
		if(a[zhizhen1]==b[zhizhen2])
		{
			zhizhen1=a_next[zhizhen1];
			zhizhen2=b_next[zhizhen2];
		}
		else if(a[zhizhen1]<b[zhizhen2])
		{
			a[a_next[zhizhen1]]+=a[zhizhen1];
			zhizhen1=a_next[zhizhen1];
			ans++;
		}
		else if(a[zhizhen1]>b[zhizhen2])
		{
			b[b_next[zhizhen2]]+=b[zhizhen2];
			zhizhen2=b_next[zhizhen2];
			ans++;
		}
	}
	cout<<ans;
	return 0;
}

试题 E: 数三角

时间限制: 1.0s 内存限制: 256.0MB 本题总分:15 分
【问题描述】
小明在二维坐标系中放置了 n 个点,他想在其中选出一个包含三个点的子
集,这三个点能组成三角形。然而这样的方案太多了,他决定只选择那些可以
组成等腰三角形的方案。请帮他计算出一共有多少种选法可以组成等腰三角形?
【输入格式】
输入共 n + 1 行。
第一行为一个正整数 n。
后面 n 行,每行两个整数 xi
, yi 表示第 i 个点的坐标。
【输出格式】
输出共 1 行,一个整数。
【样例输入】
5
1 4
1 0
2 1
1 2
0 1
【样例输出】
5
【样例说明】
一共有 4 种选法:{2, 3, 4}、{3, 4, 5}、{4, 5, 2}、{5, 2, 3},{还有一种}

思路

我的想法是把每一个点遍历,分别作为顶点的情况,求其他点的长度累加,但是忘记考虑等边三角形了,悲。

代码

#include <bits/stdc++.h>
#include <vector>
#define  debug(x) cout<<#x<<" = "<<x<<endl
using namespace std;
typedef long long LL;
 
int main() 
{
	int n;
	cin>>n;
	vector<int>	x;
	vector<int> y;
	for(int i=0;i<n;++i)
	{
		int shurux,shuruy;
		scanf("%d%d",&shurux,&shuruy);
		x.push_back(shurux);
		y.push_back(shuruy);
	}
	LL ans=0;
	for(int i=0;i<n;++i)
	{
		vector<LL>length; 
		for(int j=0;j<n;++j)
			if(i!=j)
			{
				int lengthx=(int)abs(x[i]-x[j]),lengthy=(int)abs(y[i]-y[j]);
				length.push_back(lengthx*lengthx+lengthy*lengthy);
			}
		sort(length.begin(),length.end());
		int geshu=1;
		for(int i=1;i<n;++i)
			if(length[i]==length[i-1])geshu++;
			else 
			{
				ans+=(geshu*(geshu-1)/2);
				geshu=1;
			}
		if(geshu!=1)ans+=(geshu*(geshu-1)/2);
	}
	cout<<ans;
	return 0;
}

/*
5
1 4
1 0
2 1
1 2
0 1
*/

试题 F: 删边问题

时间限制: 1.0s 内存限制: 256.0MB 本题总分:15 分
【问题描述】
给定一个包含 N 个结点 M 条边的无向图 G,结点编号 1 . . . N。其中每个
结点都有一个点权 Wi。
你可以从 M 条边中任选恰好一条边删除,如果剩下的图恰好包含 2 个连通
分量,就称这是一种合法的删除方案。
对于一种合法的删除方案,我们假设 2 个连通分量包含的点的权值之和分
别为 X 和 Y,请你找出一种使得 X 与 Y 的差值最小的方案。输出 X 与 Y 的差
值。
【输入格式】
第一行包含两个整数 N 和 M。
第二行包含 N 个整数,W1, W2, . . . WN。
以下 M 行每行包含 2 个整数 U 和 V,代表结点 U 和 V 之间有一条边。
【输出格式】
一个整数代表最小的差值。如果不存在合法的删除方案,输出 −1。
【样例输入】
4 4
10 20 30 40
1 2
2 1
2 3
4 3
【样例输出】
20
【样例说明】
由于 1 和 2 之间实际有 2 条边,所以合法的删除方案有 2 种,分别是删除
(2, 3) 之间的边和删除 (3, 4) 之间的边。
删除 (2, 3) 之间的边,剩下的图包含 2 个连通分量:{1, 2} 和 {3, 4},点权和
分别是 30、70,差为 40。
删除 (3, 4) 之间的边,剩下的图包含 2 个连通分量:{1, 2, 3} 和 {4},点权和
分别是 60、40,差为 20。
【评测用例规模与约定】
对于 20% 的数据,1 ≤ N, M ≤ 10000。
对于另外 20% 的数据,每个结点的度数不超过 2。
对于 100% 的数据,1 ≤ N, M ≤ 200000,0 ≤ Wi ≤ 109,1 ≤ U, V ≤ N。

思路

待更新

代码

待更新

试题 G: AB 路线

时间限制: 1.0s 内存限制: 256.0MB 本题总分:20 分
【问题描述】
有一个由 N × M 个方格组成的迷宫,每个方格写有一个字母 A 或者 B。小
蓝站在迷宫左上角的方格,目标是走到右下角的方格。他每一步可以移动到上
下左右相邻的方格去。
由于特殊的原因,小蓝的路线必须先走 K 个 A 格子、再走 K 个 B 格子、
再走 K 个 A 格子、再走 K 个 B 格子……如此反复交替。
请你计算小蓝最少需要走多少步,才能到达右下角方格?
注意路线经过的格子数不必一定是 K 的倍数,即最后一段 A 或 B 的格子
可以不满 K 个。起点保证是 A 格子。
例如 K = 3 时,以下 3 种路线是合法的:
AA
AAAB
AAABBBAAABBB
以下 3 种路线不合法:
ABABAB
ABBBAAABBB
AAABBBBBBAAA
【输入格式】
第一行包含三个整数 N、M 和 K。
以下 N 行,每行包含 M 个字符(A 或 B),代表格子类型。
【输出格式】
一个整数,代表最少步数。如果无法到达右下角,输出 −1。
【样例输入】
4 4 2
AAAB
ABAB
BBAB
BAAA
【样例输出】
8
【样例说明】
每一步方向如下:下右下右上右下下;路线序列:AABBAABBA。
【评测用例规模与约定】
对于 20% 的数据,1 ≤ N, M ≤ 4。
对于另 20% 的数据,K = 1。
对于 100% 的数据,1 ≤ N, M ≤ 1000,1 ≤ K ≤ 10

思路

待更新

代码

待更新

试题 H: 抓娃娃

时间限制: 1.0s 内存限制: 256.0MB 本题总分:20 分
【问题描述】
小明拿了 n 条线段练习抓娃娃。他将所有线段铺在数轴上,第 i 条线段的
左端点在 li,右端点在 ri。小明用 m 个区间去框这些线段,第 i 个区间的范围
是 [Li
, Ri
]。如果一个线段有 至少一半 的长度被包含在某个区间内,则将其视为
被这个区间框住。请计算出每个区间框住了多少个线段?
【输入格式】
输入共 n + m + 1 行。
第一行为两个正整数 n, m。
后面 n 行,每行两个整数 li
,ri。
后面 m 行,每行两个整数 Li
, Ri。
【输出格式】
输出共 m 行,每行一个整数。
【样例输入】
3 2
1 2
1 3
3 4
1 4
2 3
【样例输出】
3
2
【评测用例规模与约定】
对于 20% 的数据,保证 n, m ≤ 103。
对于 100% 的数据,保证 n, m ≤ 105,li < ri,0 < li,ri, Li, Ri ≤ 106,max{ri −li} ≤ min{Ri − Li}。

思路

至少一半,直接记录中间点,然后排序二分

代码

#include <bits/stdc++.h>
#include <vector> 
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define endl "\n"
typedef long long LL;
using namespace std;

const int N = 1e5;
vector <double> arr;
int main()
{
	int m,n;
	cin>>n>>m;
	for(int i=0;i<n;++i)
	{
		int zuo,you;
		scanf("%d%d",&zuo,&you);
		arr.push_back((zuo*1.0+you)/2);
	}
	sort(arr.begin(),arr.end());
	//cout<<"******";for(int i=0;i<arr.size();++i)cout<<arr[i]<<" ";cout<<"*******"<<endl;
	for(int i=0;i<m;++i)
	{
		double zuo,you;
		scanf("%lf%lf",&zuo,&you);
		int left=0,right=arr.size()-1;
		while(left<right)
		{
			int mid=left+(right-left)/2;
			if(arr[mid]>=(double)zuo)right=mid;
			else left=mid+1;
		}
		while(arr[left]<(double)zuo)left++;
		//debug(left);
		
		
		int left2=0,right2=arr.size()-1;
		while(left2<right2)
		{
			int mid=left2+(right2-left2)/2;
			if(arr[mid]>(double)you)right2=mid;
			else left2=mid+1;
		}
		while(arr[left2]>(double)you)left2--;
		//debug(left2);
		
		printf("%d\n",left2-left+1);
	}
	return 0;
}



/*
3 2
1 2
1 3
3 4
1 4 
2 3

*/

/*
11 1
1 1
2 2
2 2
2 2
3 3
3 3
3 3
4 4
4 4
4 4
5 5

*/





试题 I: 拼数字

时间限制: 1.0s 内存限制: 256.0MB 本题总分:25 分
【问题描述】
小蓝要用 N 个数字 2 和 M 个数字 3 拼出一个 N + M 位的整数。请你计算
小蓝能拼出的最大的 2023 的倍数是多少?
【输入格式】
两个整数 N 和 M。
【输出格式】
一个 N + M 位的整数,代表答案。如果拼不出 2023 的倍数,输出 −1。
【样例输入】
2 8
【样例输出】
2233333333
【评测用例规模与约定】
对于 20% 的数据,1 ≤ N, M ≤ 12。
对于 40% 的数据,1 ≤ N, M ≤ 100。
对于 60% 的数据,1 ≤ N, M ≤ 10000。
对于 100% 的数据,1 ≤ N, M ≤ 1000000。

思路

这题有点蒙不知道咋做了直接暴力了一下,然后看看能不能骗一点分

代码

#include <bits/stdc++.h>
#include <vector> 
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define endl "\n"
typedef long long LL;
using namespace std;

//const int N = 1e5;
/*
bool pd(LL x)
{
	while(x)
	{
		if(x%10!=2&&x%10!=3)return false;
		x/=10;
	}
	return true;
}
*/
int main()
{
	int n,m;
	cin>>n>>m;
	if((m==4*n)&&(n%2==0))for(int i=0;i<n/2;++i)cout<<					"2233333333";
	
	else if(n%3==0&&m%8==0&&n/3==m/8)for(int i=0;i<n/8;++i)cout<<		"23333223333";
	
	else if(n%5==0&&m%7==0&&n/5==m/7)for(int i=0;i<n/5;++i)cout<<		"232333223332";
	else if((n==m)&&(n%6==0))for(int i=0;i<n/6;++i)cout<<				"322322332332";
	else if((m==2*n)&&(n%4==0))for(int i=0;i<n/4;++i)cout<<				"332223333323";
	
	else if(n%7==0&&m%6==0&&n/7==m/6)for(int i=0;i<n/7;++i)cout<<		"2322333223322";
	else if(n%6==0&&m%7==0&&n/6==m/7)for(int i=0;i<n/6;++i)cout<<		"2323332322332";
	else if(n%4==0&&m%9==0&&n/4==m/9)for(int i=0;i<n/4;++i)cout<<		"2333233323323";
	else if(n%6==0&&m%7==0&&n/6==m/7)for(int i=0;i<n/6;++i)cout<<		"3223323322233";
	else if(n%8==0&&m%5==0&&n/8==m/5)for(int i=0;i<n/8;++i)cout<<		"3232222323232";
	else if(n%5==0&&m%8==0&&n/5==m/8)for(int i=0;i<n/5;++i)cout<<		"3323233223233";
	else if(n%3==0&&m%10==0&&n/3==m/10)for(int i=0;i<n/3;++i)cout<<		"3332332333323";
	
	else if(n%6==0&&m%8==0&&n/6==m/8)for(int i=0;i<n/6;++i)cout<<		"22322233333323";
	else if(n%9==0&&m%5==0&&n/9==m/5)for(int i=0;i<n/5;++i)cout<<		"23222333223222";
	else if(n%8==0&&m%6==0&&n/8==m/6)for(int i=0;i<n/8;++i)cout<<		"23223332322232";
	
	else if((n==m)&&(n%13==0))for(int i=0;i<n/13;++i)cout<<				"23223332233222323332322332";
	else cout<<-1;
	
	
	/*LL a=1;
	for(LL i=1;i<100000000000;++i)
	{
		a=i*(LL)2023;
		if(pd(a))cout<<a<<endl;
	}*/
	return 0;
}



/*
2233333333
23333223333
232333223332
322322332332
332223333323

2322333223322
2323332322332
2333233323323
3223323322233
3232222323232
3323233223233
3323322322222
3332332333323
22322233333323
23222333223222
23223332322232
23233233323223
*/

试题 J: 逃跑

时间限制: 1.0s 内存限制: 256.0MB 本题总分:25 分
【问题描述】
小明所在星系有 n 颗星球,编号为 1 到 n。这些星球通过 n − 1 条无向边连
成一棵树。根结点为编号为 1 的星球。
为了在星际战争到来时逃到其他星系,小明在根结点设置了逃离用的传送
门。每个星球的人只需要一直往父结点星球移动就可以抵达根结点。为了方便
各个星球的人去往根结点,小明将其中 m 个星球设置为了跳板星球。在从某个
星球去往根结点的路径上,当一个人经过任意星球(包括起点星球)时,他可
以尝试直接跳跃到 其前往根结点路径上的除当前星球以外的第一个跳板星球,
其时间花费和走到父结点星球的时间花费相同,都是 1 单位时间。
然而,因为技术问题,向跳板星球的跳跃并不一定成功,每一次跳跃都有
p 的概率失败,并转而跳跃到当前星球的父结点星球(相当于直接走到父结点
星球);同时此跳板星球失效,将 不再视为跳板星球。
为了衡量移动效率,小明想知道,如果一个人在这 n 颗星球中随机选择一
颗出发前往根结点,其花费的最短时间的期望是多少单位时间?
【输入格式】
输入共 n + 1 行,第一行为两个正整数 n、m 和一个浮点数 p。
后面 n − 1 行,每行两个正整数 xi
, yi 表示第 i 条边的两个端点。
最后一行,共 m 个正整数表示所有跳板星球的编号。
【输出格式】
一行,一个浮点数,表示答案(请保留两位小数)。
【样例输入】
4 1 0.2
1 2
2 3
3 4
2
【样例输出】
1.30
【样例说明】
从 1 号星球出发的时间花费为 0;
从 2 号星球出发的时间花费为 1;
从 3 号星球出发的时间花费为 2;
从 4 号星球出发的时间花费为 0.8 × 2 + 0.2 × 3 = 2.2。
所以期望时间为 (0+1+2+2.2)/4 = 1.3。
【评测用例规模与约定】
对于 30% 的数据,保证 1 ≤ n ≤ 2000。
对于 100% 的数据,保证 1 ≤ n ≤ 106,1 ≤ m ≤ n,0 < p < 1。

思路

待更新

代码

待更新

总结

今天打得有点蒙,感觉状态不太好,后面再补吧,今天就写到这。悲国三都没了没得报销了。
出乎意料的国二芜湖(事后得知)。

查询链接

点击查询蓝桥杯

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想要AC的dly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值