您现在的位置是:首页 >技术交流 >2023第十四届蓝桥杯国赛 C/C++ 大学 B 组网站首页技术交流

2023第十四届蓝桥杯国赛 C/C++ 大学 B 组

尘_客 2024-10-14 12:01:04
简介2023第十四届蓝桥杯国赛 C/C++ 大学 B 组

 省赛还水了个省一,国赛原型毕露了

参考文献:(13条消息) 2023第十四届蓝桥杯国赛 C/C++ 大学 B 组_旧林墨烟的博客-CSDN博客

(13条消息) 2023第十四届蓝桥杯国赛 C/C++ 大学 B 组 (赛后记录)_.Zero的博客-CSDN博客

A:子2023 

【问题描述】
小蓝在黑板上连续写下从 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]…

暴力枚举 +剪枝  (考试的时候怎么就没敢做哪?)

答案:5484660609

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
typedef long long ll;
#define x first 
#define y second 
typedef pair<int,int>PII;
ll sum,cnt,target;
ll dp[2500][20]; 
int main()
{
	string s;
	for(int i=1;i<=2023;i++)
	{
		int x=i;
		string t=to_string(i);
		for(int j=0;j<t.size();j++)
		{//光把数字中的2/3/0加进来,剪枝 
			if(t[j]=='2'||t[j]=='3'||t[j]=='0')s+=t[j];
		}
	}
	ll cnt=0;
	int n=s.size();
	cout<<s<<endl;
	for(int i=0;i<n;i++)
	{
		if(s[i]=='2')
		{
			for(int j=i+1;j<n;j++)
			{
				if(s[j]=='0')
				{
					for(int k=j+1;k<n;k++)
					{
						if(s[k]=='2')
						{
							for(int p=k+1;p<n;p++)
							{
								if(s[p]=='3')cnt++;
							}
						}
					}
				}
			}
		}
	}
	cout<<cnt;
	return 0;
}

 dp 上面链接大佬的思路,太牛了

当遇到字符 ‘2’ 的时候字符串 “2” 的数量+1,字符串 “202” 的数量加上字符串 “20” 的数量
当遇到字符 ‘0’ 的时候字符串 “20” 的数量加上字符串 “2” 的数量
当遇到字符 ‘3’ 的时候字符串 “2023” 的数量加上字符串 “202” 的数量
最后 “2023” 的数量就是答案

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
typedef long long ll;
#define x first 
#define y second 
typedef pair<int,int>PII;
ll sum,cnt,target;
ll dp[4]; //dp四个分别代表 '2' ,'20' ,'202' ,'2023'的数量 
int main()
{
	string s;
	for(int i=1;i<=2023;i++)
	{
		int x=i;
		string t=to_string(i);
		for(int j=0;j<t.size();j++)
		{//光把数字中的2/3/0加进来,剪枝 
			if(t[j]=='2'||t[j]=='3'||t[j]=='0')s+=t[j];
		}
	}
	int n=s.size();
	for(int i=0;i<n;i++)
	{
		if(s[i]=='2')
		{
			dp[0]++;//'2'数量++ 
			dp[2]+=dp[1]; //进来一个2,'202'数量加上'20'的数量	
		}	
		else if(s[i]=='0')
		{
			dp[1]+=dp[0];//进来一个0,'20'数量加上‘2’的数量 
		}
		else if(s[i]=='3')
		{
			dp[3]+=dp[2]; //进来一个3,'2023'数量加上'202'数量 
		}
	}
	cout<<dp[3]; 
	return 0;
}

B: 双子数

【问题描述】
  若一个正整数 x 可以被表示为 p2 × q2,其中 p、q 为质数且 p , q,则 x 是一个 “双子数”。请计算区间 [2333, 23333333333333] 内有多少个 “双子数”?

考试的时候暴力没搜出来--  以后要习惯暴力找剪枝

long long 开不下prime[i]*prime[i]*prime[j]*prime[j]   错误结果是 947293

要用__int128   

答案  947293

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
typedef long long ll;
#define x first 
#define y second 
#define int __int128
typedef pair<int,int>PII;
ll sum,cnt,target;
bool isPrime(ll x)
{
	if(x==2||x==3||x==5)return true;
	for(ll i=2;i<=sqrt(x);i++)
	{
		if(x%i==0)return false;
	} 
	return true;
}
signed main()
{
	vector<int>prime;
	ll left=2333,right=23333333333333;
	for(int i=2;i<=sqrt(right);i++)
	{//不会用筛 就暴力了 
		if(isPrime(i))
		prime.push_back(i);
	}
	cout<<"hehe
";
	for(int i=0;i<prime.size();i++)
	{
		for(int j=i+1;j<prime.size();j++)
		{
			int res=prime[i]*prime[i]*prime[j]*prime[j];
			if(res>=left&&res<=right)cnt++;
			if(res>right)break;//大于直接退出 ,后面的更大,所以后面没答案 ——剪枝 
		}
	}
	cout<<cnt;
	return 0;
}

C题 班级活动

找规律     

sum1存人数多于两个的人数去掉匹配的 2 位剩下的总人数 下面记作集合S 
    sum2存储出现一次的, 这是单个的需要处理的    下面记作集合V
    如果sum1>=sum2  res=sum1 把集合S中的和V中的匹配sum1-sum2个,剩下S的sum2个两两匹配成其他未出现的数
    例子 1 1 1 1  1 2 2 2 3 4  
    需处理的是 1 1  1 2, 3 4  把左边任意两个和右边两个匹配(1 1 便 3 4),左边剩下两个随便换一个(1 2 换 6 6(没出现的都行)) 
    如果sum1<sum2  S和V所有匹配,V剩下的两两匹配 
    1 1 1 2 2 2 2 3 4 5 6  7
    需要处理 1  2 2 ,3 4 5 6 7 
    把左边三个和右面三个匹配(1 2 2 变为 3 4 5),右面剩下两个自己匹配 (6 7 变 6 6)

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
#define x first 
#define y second 
#define int long long
typedef pair<int,int>PII;
signed main()
{
	int n;
	cin>>n;
	map<int,int>mymap;
	for(int i=0;i<n;i++)
	{
		int x;
		cin>>x;
		mymap[x]++;
	}
	int sum1=0,sum2=0;
	/*sum1存人数多于两个的人数去掉匹配的 2 位剩下的总人数 下面记作集合S 
	sum2存储出现一次的, 这是单个的需要处理的    下面记作集合V
	如果sum1>=sum2  res=sum1 把集合S中的和V中的匹配sum1-sum2个,剩下S的sum2个两两匹配成其他未出现的数
	例子 1 1 1 1  1 2 2 2 3 4  
	需处理的是 1 1  1 2, 3 4  把左边任意两个和右边两个匹配(1 1 便 3 4),左边剩下两个随便换一个(1 2 换 6 6(没出现的都行)) 
	如果sum1<sum2  S和V所有匹配,V剩下的两两匹配 
	1 1 1 2 2 2 2 3 4 5 6  7
	需要处理 1  2 2 ,3 4 5 6 7 
	把左边三个和右面三个匹配(1 2 2 变为 3 4 5),右面剩下两个自己匹配 (6 7 变 6 6)
	*/
	for(auto it:mymap)
	{//遍历出现过的所有数字 
		if(it.second>=2)sum1+=it.second-2;
		else sum2+=it.second;
	}
	if(sum1>=sum2)cout<<sum1<<endl;
	else cout<<(sum1+(sum2-sum1)/2); 
	return 0;
}

D题 合并数列

 贪心 ——小的合并 (用队列模拟)

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
#define x first 
#define y second 
#define int long long
typedef pair<int,int>PII;
signed main()
{
	int n,m;
	cin>>n>>m;
	queue<int>q1;
	queue<int>q2;
	int v;
	for(int i=0;i<n;i++)
	{
		cin>>v;
		q1.push(v);
	}
	for(int i=0;i<m;i++)
	{
		cin>>v;
		q2.push(v);
	}
	int cnt=0;
	while(q1.size()&&q2.size())
	{
		int top1=q1.front(); 
		int top2=q2.front(); 
		if(top1==top2)
		{//相等都出队 
			q2.pop();
			q1.pop();
		}
	
		else if(top1<top2)
		{//top1小 所以q1前两个合并 
			q1.pop();
			q1.front()+=top1;
			cnt++;
		}
		else 
		{//top2小 所以q2前两个合并 
			q2.pop();
			q2.front()+=top2;
			cnt++;
		}
	}
	cout<<cnt<<endl;
	return 0;
}

 

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。