2019年蓝桥杯国赛C/C++B组真题部分解析

2019年蓝桥杯国赛C/C++B组真题部分解析

A-平方序列
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

小明想找到两个正整数 X 和 Y ,满足
1、2019 2、20192(平方)、X2(平方)、Y2(平方)构成等差数列
请你求出在所有可能的解中,X+Y的最小值是多少?
组成等差数列。
请你求出在所有可能的解中,X +Y 的最小值是多少?

运行限制
最大运行时间:1s
最大运行内存: 128M

思路:
根据等差数列的性质得出XY之间的关系 如代码

#include
using namespace std;
int main(){
	for(int i=2020;;i++){
		int yy=2*i*i-2019*2019;//根据等差数列得出
		int y=sqrt(yy);
		if(y*y==yy){
			cout<<i+y<<endl;
			return 0;//7020
		}
	}
	return 0;
}

B-质数拆分
将2019拆分为若干个两两不同的质数之和,一共有多少种不同的方法?注意交换顺序视为同一种方法,例如2 + 2017 = 2019与2017 + 2 = 2019视为同一种方法。

思路:
把1~2019所有的素数都保存下来在一个数组里,只需要最后组成的合为2019即可,就变成从素数里选 然后组成2019,和背包问题相似

#include
using namespace std;
int zhishu[2000];
int step=0;//存质数的下标 
long long save[3000][3000];//记忆化搜索 缩短时间 不然会超时算不出
void get(){
	for(int i=2;i<2019;i++){
		int flag=1;
		for(int j=2;j*j<=i;j++){
			if(i%j==0){
				flag=0;
				break;
			}
		}
		if(flag){
			zhishu[step++]=i;
		}
	}
}
long long find(int pos,long long sum){
	if(sum==2019){
		return 1;
	}
	if(pos>=step||sum>2019){
		return 0;
	}
	if(save[pos][sum]!=0){
		return save[pos][sum];
	}
	
	long long ans1=0;
	ans1+=find(pos+1,sum);
	ans1+=find(pos+1,sum+zhishu[pos]);
	save[pos][sum]=ans1;
	return ans1;
}
int main(){
	get();
	cout<<find(0,0)<<endl; //答案55965365465060
	return 0;
}

C-拼接
D-求值
学习了约数后,小明对于约数很好奇,他发现,给定一个正整数t,总是可以找到含有t个约数的整数。小明对于含有t个约数的最小数非常感兴趣,并把它定义为St。例如S1= 1,S2= 2,S3= 4,S4= 6,。现在小明想知道,当t= 100时,St是多少?即S100是多少?
思路:
这题的思路感觉就是暴力搜,找出满100个约数的数。

#include
using namespace std;
int main(){
	int sum=100;
	for(int i=2;;i++){
		int ans=0;
		for(int j=2;j<i;j++){
			if(i%j==0){
				ans++;
			}
		}
		if(ans+2==sum){ //+2是因为还有一和他自身 
			cout<<i<<endl; //45360
			return 0;
		}
	}
	return 0;
}

这里有个求一个数有多少约数的代码 有兴趣可以看看
有一个公式就是说
6=21 * 31 所以6的约数数目为 (1+1)(1+1)=4
8=23 所以8的约数数目为(3+1)=4

#include
using namespace std;
int size[50000];
int main(){
	int num=45360; //可以随便更换 要是太大的话记得开longlong
	for(int i=2;i*i<=num;i++){
		while(num%i==0){
			size[i]++;
			num/=i;
		}
	}
	if(num!=1){
		size[num]++;
	}
	int ans=1;
	for(int i=2;i<=45360;i++){
		if(size[i]){
			ans*=(size[i]+1);
		}
	}
	cout<<ans<<endl; //得出是100正确
	return 0;
} 

E-路径计数
有一个7X7的方格。方格左上角顶点坐标为(0,0),右下角坐标为(7,7)。
求满足下列条件的路径条数:
1、起点和终点都是(0,0)
2、路径不自交
3、路径长度不大于12
4、对于每一个顶点,有上下左右四个方向可以走,但是不能越界。
思路
其实6X6和7X… 更大的方格都是一样的 最大12步会有限制最远到达的地方
在6X6时候就已经到了最大

#include
using namespace std;
int vis[9][9];
int ans=0;
int xx[4]={0,0,-1,1};
int yy[4]={1,-1,0,0};
bool val(int x,int y,int step){
	if(x<0||x>6||y<0||y>6){
		return false;
	}
	if(vis[x][y]==1) return false;
	if(step>12){
		return false;
	}
	return true;
}
void dfs(int x,int y,int step){
	if(x==0&&y==0&&step!=2&&step!=0){
		ans++;
		return;
	}
	for(int i=0;i<4;i++){
		int x1=x+xx[i];
		int y1=y+yy[i];
		if(val(x1,y1,step+1)){
			vis[x1][y1]=1;
			dfs(x1,y1,step+1);
			vis[x1][y1]=0;
		}
	}
}
int main(){
	dfs(0,0,0);
	cout<<ans<<endl; //206
	return 0;
} 

F-最优包含
题目给定两个字符串S和T,保证S的长度不小于T的长度,问至少修改S的多少个字符,可以令T成为S的子序列。

输入描述:
两行。
第一行是字符串S,第二行是字符串T。
保证S的长度不小于T的长度,S的长度范围在10~1000之间。
输出描述:
答案,一个非负整数。
输入样例:
XBBBBBAC
ACC
输出样例:
2
思路
用dp[i][j] i 代表第一行字符串下标 j代表第二行字符串下标
dp[i][j]表示用i个字符最优包含j个字符的最小修改数
当第一行第i个 等于第二行第j个时结果不变即dp[i][j]=dp[i-1][j-1];
当不相等时 dp[i][j]=min(dp[i-1][j],dp[i-1][j-1]+1)

#include
using namespace std;
int dp[1005][1005];
int main(){
	string s1,s2,str1,str2;
	cin>>str1>>str2;
	s1="a"+str1;
	s2="b"+str2;
	memset(dp,0x3f3f3f3f,sizeof dp);
	dp[0][0]=0;
	for(int j=1;j<s2.size();j++){
		for(int i=j;i<s1.size();i++){
			if(s1[i]==s2[j]){
				dp[i][j]=dp[i-1][j-1];
			}else{
				dp[i][j]=min(dp[i-1][j-1]+1,dp[i-1][j]);
			}
		}
	}
	cout<<dp[s1.size()-1][s2.size()-1]<<endl;
	return 0;
}

G-排列数
对于一个数列中的某个数,如果这个数比两侧的数都大或比两侧的数都小,我们称这个数为这个数列的一个转折点。
如果一个数列有t个转折点,我们称这个数列为t+1调数列。
给定两个正整数n,k。求在1~n的全排列中,有多少个数列是k调数列。
输入描述:
两个正整数n,k。

输出描述:
答案,一个整数。

输入样例:
4 2
1
输出样例:
12
思路
对n个数进行全排 如果满足k 答案+1 最后输出答案

#include
using namespace std;
typedef long long ll;
ll ans1=0;
int n,k;
int vis[1005];
ll get(vector<int>ans){
	if(ans.size()<n){
		return 0;
	}
	int k=1;
	for(int i=1;i<ans.size()-1;i++){
		if(ans[i]>ans[i-1]&&ans[i]>ans[i+1]){
			k++;
		}else if(ans[i]<ans[i-1]&&ans[i]<ans[i+1]){
			k++;
		}
	}
	return k;
}
void find(vector<int>ans){
	if(ans.size()==n){
		if(get(ans)==k)
			ans1++;
		return;
	}
	for(int i=1;i<=n;i++){
		if(vis[i]!=1){
			ans.push_back(i);
			vis[i]=1;
			find(ans);
			ans.pop_back();
			vis[i]=0;
		}
	}
}
int main(){
	cin>>n>>k;
	vector<int>ans;
	find(ans);
	cout<<ans1%123456<<endl;
	return 0;
} 

H-解谜游戏
小明正在玩一款解谜游戏。谜题由24根塑料棒组成,其中黄色塑料棒4根,红色8根,绿色12根(后面用Y表示黄色、R表示红色、G表示绿色)。初始时这些塑料棒排成三圈,如上图所示,外圈12根,中圈8根,内圈4根。小明可以进行三种操作:

1.将三圈塑料棒都顺时针旋转一个单位。例如当前外圈从0点位置开始顺时针依次是YRYGRYGRGGGG,中圈是RGRGGRRY,内圈是GGGR。那么顺时针旋转一次之后,外圈、中圈、内圈依次变为:GYRYGRYGRGGG、YRGRGGRR和RGGG。

2.将三圈塑料棒都逆时针旋转一个单位。例如当前外圈从0点位置开始顺时针依次是YRYGRYGRGGGG,中圈是RGRGGRRY,内圈是GGGR。那么逆时针旋转一次之后,外圈、中圈、内圈依次变为:RYGRYGRGGGGY、GRGGRRYR和GGRG

3.将三圈0点位置的塑料棒做一个轮换。具体来说:外圈0点塑料棒移动到内圈0点,内圈0点移动到中圈0点,中圈0点移动到外圈0点。例如当前外圈从0点位置开始顺时针依次是YRYGRYGRGGGG,中圈是RGRGGRRY,内圈是GGGR。那么轮换一次之后,外圈、中圈、内圈依次变为:RRYGRYGRGGGG、GGRGGRRY和YGGR。小明的目标是把所有绿色移动到外圈、所有红色移动中圈、所有黄色移动到内圈。给定初始状态,请你判断小明是否可以达成目标。

输入描述:
第一行包含一个整数T,代表询问的组数。(1

输出描述:
对于每组询问,输出一行YES或者NO,代表小明是否可以达成目标。
2
GYGGGGGGGGGG
RGRRRRRR
YRYY
YGGGRRRRGGGY
YGGGRRRR
YGGG
1
2
3
4
5
6
7
输出样例:
YES
NO

思路
其实有个规律就是以四个字符为一组
外圈1 2 3 4 1 2 3 4 1 2 3 4
中圈1 2 3 4 1 2 3 4
内圈1 2 3 4
它们的1234下标分别对齐 通过旋转可以变换对齐
所以可以分为4组
每组的G=3 R=3 Y=1才能解密成功 根据这一条件

#include
using namespace std;
int main(){
	int n;
	cin>>n;
	while(n--){
		string s1,s2,s3;
		cin>>s1>>s2>>s3;
		int flag=1;
		for(int i=0;i<4;i++){
			map<char,int>mp;
			//内圈 
			mp[s3[i]]++;
			//中圈 
			mp[s2[i]]++;
			mp[s2[i+4]]++;
			//外圈 
			mp[s1[i]]++;
			mp[s1[i+4]]++;
			mp[s1[i+8]]++;
			if(mp['G']!=3||mp['R']!=2||mp['Y']!=1){
				flag=0;
				break;
			}
		}
		if(flag) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

I-第八大奇迹
J-燃烧权杖

你可能感兴趣的:(蓝桥杯,2019,c++)