蓝桥杯校内模拟赛_C++组

蓝桥杯校内模拟赛

填空题

填空题比较简单,只需要在空格中填写整数答案即可:

  1. 在计算机存储中,15.125GB是多少MB?
    解题思路: 1GB=1024MB,打开系统计算器计算即可
    答案: 15488
  2. 在1至2019中,有多少个数的数位中包含数字9?
    解题思路: 需要注意如果一个数字中包含多个9也只计一个,写一个循环不停取余判断即可
    答案: 544
  3. 1200000有多少个约数?
    解题思路: 直接暴力写循环一个一个判断计数即可
    答案: 96
  4. 一棵包含有2019个结点的树,最多包含多少个叶结点?
    解题思路: 题目并未说明是二叉树,所以最多可以只有一个根节点,其余全为叶节点
    答案: 2018

编程题

  1. 问题描述:
    一个正整数如果任何一个数位不大于右边相邻的数位,则称为一个数位递增的数,例如1135是一个数位递增的数,而1024不是一个数位递增的数。给定正整数 n,请问在整数 1 至 n 中有多少个数位递增的数?

    输入格式:输入的第一行包含一个整数 n。

    输出格式:输出一行包含一个整数,表示答案。

    样例输入:

    30
    样例输出:

    26
    评测用例规模与约定:对于 40% 的评测用例,1 <= n <= 1000。对于 80% 的评测用例,1 <= n <= 100000。对于所有评测用例,1 <= n <= 1000000。
    解题思路:
    这道题只需要暴力枚举每一个数,再判断这个数字是不是数位递增的数,写个循环不断取余进行每一位每一位的比较判断即可
    答案:

    #include<iostream>
    using namespace std;
    int main(){
    	int number;cin>>number;int times=0;
    	for(int i=1;i<=number;i++){
    		if(i<10){//个位数成立 
    			times++;
    		}
    		else{
    			int a=i%10;int b=i/10;int judge=0;
    			while(b>0){
    				if(a<b%10){
    					//不成立的情况 
    					judge=1;break;
    				}
    				else{
    					a=b%10;b=b/10;
    				}
    			}
    			if(judge==0){
    				times++;
    			}
    		}
    	}
    	cout<<times<<endl;
    	return 0;
    } 
    
  2. 问题描述:
    问题描述:在数列 a[1], a[2], …, a[n] 中,如果对于下标 i, j, k 满足 0<i<j<k<n+1 且 a[i]<a[j]<a[k],则称 a[i], a[j], a[k] 为一组递增三元组,a[j]为递增三元组的中心。给定一个数列,请问数列中有多少个元素可能是递增三元组的中心。

    输入格式:输入的第一行包含一个整数 n。第二行包含 n 个整数 a[1], a[2], …, a[n],相邻的整数间用空格分隔,表示给定的数列。

    输出格式:输出一行包含一个整数,表示答案。
    样例输入:

    5
    1 2 5 3 5
    样例输出:

    2
    样例说明:a[2] 和 a[4] 可能是三元组的中心。

    评测用例规模与约定:对于 50% 的评测用例,2 <= n <= 100,0 <= 数列中的数 <= 1000。对于所有评测用例,2 <= n <= 1000,0 <= 数列中的数 <= 10000。
    解题思路:
    利用一个vector存储数据,我们写个循环遍历除去首尾的数字,因为首尾不可能成为三元组中心,我的想法是,循环到一个元素,将这个元素的前面所有元素升序排序,将这个元素的后面所有元素升序排序,然后判断该元素是否大于前面的最小值且小于后面的最大值,如果满足则计数加一,最后输出即可,这里选用vector主要是个人习惯,采取数组也是一样的
    答案:

    #include<iostream>
    using namespace std;
    #include<vector>
    #include<algorithm>
    int main(){
    	int n;cin>>n;
    	vector<int> arr;
    	for(int i=0;i<n;i++){
    		int now;cin>>now;
    		arr.push_back(now);
    	}
    	int times=0;
    	vector<int> now;
    	now.assign(arr.begin(),arr.end());
    	for(int i=1;i<arr.size()-1;i++){
    		arr.assign(now.begin(),now.end());
    		sort(arr.begin(),arr.begin()+i-1);
    		sort(arr.begin()+i+1,arr.end());
    		if(arr[i]>arr[0]&&arr[i]<arr[i+1]){
    			times++;
    		}
    	}
    	cout<<times<<endl;
    	return 0;
    }
    
  3. 问题描述:
    小明要组织一台晚会,总共准备了 n 个节目。然后晚会的时间有限,他只能最终选择其中的 m 个节目。这 n 个节目是按照小明设想的顺序给定的,顺序不能改变。小明发现,观众对于晚上的喜欢程度与前几个节目的好看程度有非常大的关系,他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。小明给每个节目定义了一个好看值,请你帮助小明选择出 m 个节目,满足他的要求。

    输入格式:输入的第一行包含两个整数 n, m ,表示节目的数量和要选择的数量。第二行包含 n 个整数,依次为每个节目的好看值。

    输出格式:输出一行包含 m 个整数,为选出的节目的好看值。
    样例输入:

    5 3
    3 1 2 5 4
    样例输出:

    3 5 4
    样例说明:选择了第1, 4, 5个节目。

    评测用例规模与约定:对于 30% 的评测用例,1 <= n <= 20;对于 60% 的评测用例,1 <= n <= 100;对于所有评测用例,1 <= n <= 100000,0 <= 节目的好看值 <= 100000。
    解题思路:
    之前校内选拔赛遇到过这道题,当时采用的两个一维数组,一个存储数值一个存储对应的次序,进行排序后按次序输出前m个,但是这个方法说实话有点绕,这次直接采用类,写一个类,属性为数值和次序,然后利用vector来存储类对象,先利用数值属性进行降序排列,再把前m个元素赋值给另外一个vector,再利用次序数据对新的vector进行升序排序,然后输出即可
    答案:

    #include<iostream>
    using namespace std;
    #include<vector>
    #include<algorithm>
    class see{
    	private:
    		int value;
    		int time;
    	public:
    		see(int a,int b){
    			value=a;time=b;
    		}
    		int get_value(){
    			return value;
    		}
    		int get_time(){
    			return time;
    		}
    };
    bool compare(see a,see b){
    	return a.get_value()>b.get_value();
    }
    bool recompare(see a,see b){
    	return a.get_time()<b.get_time();
    }
    int main(){
    	int n,m;cin>>n>>m;
    	vector<see> arr;
    	for(int i=0;i<n;i++){
    		int number;cin>>number;
    		see mysee(number,i);
    		arr.push_back(mysee);
    	}
    	sort(arr.begin(),arr.end(),compare);
    	vector<see> result;
    	for(int i=0;i<m;i++){
    		result.push_back(arr[i]);
    	}
    	sort(result.begin(),result.end(),recompare);
    	for(int i=0;i<m;i++){
    		cout<<result[i].get_value()<<" ";
    	}
    	return 0;
    }
    
  4. 问题描述:
    小明对类似于 hello 这种单词非常感兴趣,这种单词可以正好分为四段,第一段由一个或多个辅音字母组成,第二段由一个或多个元音字母组成,第三段由一个或多个辅音字母组成,第四段由一个或多个元音字母组成。给定一个单词,请判断这个单词是否也是这种单词,如果是请输出yes,否则请输出no。(元音字母包括 a, e, i, o, u,共五个,其他均为辅音字母。)

    输入格式:输入一行,包含一个单词,单词中只包含小写英文字母。

    输出格式:输出答案,或者为yes,或者为no。

    样例输入:

    lanqiao
    样例输出:

    yes
    样例输入:

    world
    样例输出:

    no
    评测用例规模与约定:对于所有评测用例,单词中的字母个数不超过100。
    解题思路:
    这道题也很简单,只需要对字符串进行遍历,如果遇到s[i]和s[i+1]两者一个是元音字母一个是辅音字母即可计数加一,再通俗点说,遇到前后不一致的时候就加一,如果遍历结束的计数值不为3(从0开始计数)则表示不符合题意,这里也需要注意,满足条件的字符串第一个字母必须是辅音字母,否则都不用进行判断
    答案:

    #include<iostream>
    using namespace std;
    #include<string>
    int judge(char c){
    	if(c=='a'||c=='e'||c=='i'||c=='o'||c=='u'){
    		return 1;//元音字母 
    	}
    	else{
    		return 0;//辅音字母 
    	} 
    }
    int main(){
    	string s;cin>>s;
    	if(judge(s[0])==1){
    		cout<<"no"<<endl;
    	}
    	else{
    		int times=0;
    		for(int i=0;i<s.length()-1;i++){
    			if(judge(s[i])!=judge(s[i+1])){
    				times++;
    			} 
    		}
    		if(times==3){
    			cout<<"yes"<<endl;
    		}
    		else{
    			cout<<"no"<<endl;
    		}
    	}
    	return 0;
    }
    
  5. 问题描述:
    问题描述:小明想知道,满足以下条件的正整数序列的数量:1. 第一项为 n;2. 第二项不超过 n;3. 从第三项开始,每一项小于前两项的差的绝对值。请计算,对于给定的 n,有多少种满足条件的序列。

    输入格式:输入一行包含一个整数 n。

    输出格式:输出一个整数,表示答案。答案可能很大,请输出答案除以10000的余数。

    样例输入:

    4
    样例输出:

    7
    样例说明:

    以下是满足条件的序列:

    4 1
    4 1 1
    4 1 2
    4 2
    4 2 1
    4 3
    4 4
    评测用例规模与约定:对于 20% 的评测用例,1 <= n <= 5;对于 50% 的评测用例,1 <= n <= 10;对于 80% 的评测用例,1 <= n <= 100;对于所有评测用例,1 <= n <= 1000。
    解题思路:
    这道题就比较灵性了,之前校内选拔赛遇到过一次,那时候第一反应是递归,递归编写难度其实不大,运行发现100算不出来了已经,递归是真的费时间啊,然后实在没办法,手动暴力枚举了前七个数据随便交上去得了,山水有相逢,这次又遇到了,认真对待一波,拿到题的第一反应还是递归求解,利用vector方便递归的操作实现,刷刷几分钟写好,很明显是超时的,可以看到递归过程中,我们其实没有必要把每种情况都列举出来,我们只需要的是结果,也就是到底有几种可能,很明显采用动态规划可以节约很多时间
    我之前也没有接触过动态规划,毕竟是个菜鸡,只是随随便便写写题,只会用用数组、字符串瞎解决问题,于是我去了解了下动态规划,最后得出结论,动态规划其实就是遇到这种只需要结果的,并且前后数据之间存在某种关系的问题,尝试写一个递推公式,再寻找初值,循环求解即可
    这个题算是这次模拟赛最难的一个题了,动态规划题目通常你需要考虑三个问题:
    1、用什么数据结构来表示,一维数组还是二维数组,每一个元素的含义是什么?
    2、元素之间的递推关系是什么,也就是递推公式怎么来?
    3、初始值应该有哪些?
    针对本题,我们递归不能白写,很容易想到要求5的可能次数,我们需要分别把以5 1、5 2、5 3、5 4、5 5开头的所有可能次数相加即可,所以递归程序改为如下:

    #include<iostream>
    using namespace std;
    #include<vector>
    #include<cmath>
    #include<iomanip>
    int times=0;
    int find(vector<int> a){
    	int flag=a.size();
    	if(fabs(a[flag-2]-a[flag-1])<=1){
    		//结束6
    	}
    	else{//未结束 
    		for(int i=1;i<fabs(a[flag-2]-a[flag-1]);i++){
    			vector<int> b;b.assign(a.begin(),a.end());
    			b.push_back(i);
    			find(b);times++;
    		} 
    	} 
    }
    int main(){
    	int n=10;
    	int data[n][n];
    	for(int h1=0;h1<n;h1++){
    		for(int h2=0;h2<n;h2++){
    			times=0;vector<int> arr;
    			arr.push_back(h1+1);arr.push_back(h2+1);
    			for(int i=1;i<fabs(h1-h2);i++){
    				vector<int> b;b.assign(arr.begin(),arr.end());
    				b.push_back(i);
    				find(b);times++;
    			}
    			data[h1][h2]=times+1;
    		}
    	}
    	for(int i=0;i<=n;i++){
    		cout<<setw(4)<<i<<" ";
    	}
    	cout<<endl;
    	for(int i=0;i<=n;i++){
    		cout<<"-----";
    	}
    	cout<<endl;
    	for(int i=0;i<n;i++){
    		cout<<setw(4)<<i+1<<"|";
    		for(int j=0;j<n;j++){
    			cout<<setw(4)<<data[i][j]<<" ";
    		}
    		cout<<endl;
    	}
    	return 0;
    }
    

    由此我们可以得到如下结果:
    二维数组
    如图,输出结果中的dp[i][j]代表以i j开头的字符串可能的个数,那么dp[i][j]的值怎么递推出来呢,这里直接给出,想要理解也很简单,尝试去求解以10 1开头的字符串可能个数你便会顿悟,递推公式如下:
    递推公式
    然后我们随便定好初值,进行循环求解即可,但是我们的循环需要先求解行再求解列,具体可以看看程序,当然最后肯定还是能优化的,但这道题有这个速度应该是没问题了
    测试结果
    答案:

    #include<iostream>
    using namespace std;
    #include<cmath>
    long long dp[1001][1001];
    int main(){
    	dp[1][1]=1;dp[1][2]=1;dp[1][3]=3;
    	dp[2][1]=1;dp[2][2]=1;dp[2][3]=1;
    	dp[3][1]=2;dp[3][2]=1;dp[3][3]=3;
    	int n;cin>>n;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=i;j++){
    			if(fabs(i-j)<=1){
    				dp[i][j]=1;
    			}
    			else{
    				dp[i][j]=1;
    				for(int k=1;k<=fabs(i-j)-1;k++){
    					dp[i][j]+=dp[j][k];
    				}
    			}
    		}
    		for(int j=1;j<=i;j++){
    			if(fabs(i-j)<=1){
    				dp[j][i]=1;
    			}
    			else{
    				dp[j][i]=1;
    				for(int k=1;k<=fabs(i-j)-1;k++){
    					dp[j][i]+=dp[i][k];
    				}
    				dp[j][i]=dp[j][i]%10000;
    			}
    		}
    	}
    	int result=0;
    	for(int j=1;j<=n;j++){
    		result+=dp[n][j];
    		result=result%10000;
    	}
    	cout<<result<<endl;
    	return 0;
    }
    
  6. 问题描述:
    小明有一块空地,他将这块空地划分为 n 行 m 列的小块,每行和每列的长度都为 1。小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,这四小块空地都将变为有草的小块。请告诉小明,k 个月后空地上哪些地方有草。

    输入格式:输入的第一行包含两个整数 n, m。接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。接下来包含一个整数 k。

    输出格式:输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。

    样例输入:

    4 5
    .g…

    …g…

    2
    样例输出:

    gggg.
    gggg.
    ggggg
    .ggg.
    评测用例规模与约定:对于 30% 的评测用例,2 <= n, m <= 20。对于 70% 的评测用例,2 <= n, m <= 100。对于所有评测用例,2 <= n, m <= 1000,1 <= k <= 1000。
    解题思路:
    这个题比起上一个题就很简单了,直接模拟就行,但是需要注意的情况是,能够往周围延申的草必须是上一个月存在的草,以及要注意数组下标的问题,下标不该减的时候就别去减了,代码如下:
    答案:

    #include<iostream>
    using namespace std;
    #include<vector>
    #include<string> 
    int main(){
    	int n,m;cin>>n>>m;
    	vector<int> arr[n];
    	for(int i=0;i<n;i++){
    		string s;cin>>s;
    		for(int j=0;j<s.length();j++){
    			if(s[j]=='.'){
    				arr[i].push_back(-1);
    			}
    			if(s[j]=='g'){
    				arr[i].push_back(0);
    			}
    		}
    	}
    	int k;cin>>k;
    	for(int c=1;c<k+1;c++){
    		for(int i=0;i<n;i++){
    			for(int j=0;j<m;j++){
    				if(arr[i][j]>=0&&arr[i][j]!=c){
    					if(i-1>=0&&arr[i-1][j]==-1){
    						arr[i-1][j]=c;
    					}
    					if(i+1<n&&arr[i+1][j]==-1){
    						arr[i+1][j]=c;
    					}
    					if(j-1>=0&&arr[i][j-1]==-1){
    						arr[i][j-1]=c;
    					}
    					if(j+1<m&&arr[i][j+1]==-1){
    						arr[i][j+1]=c;
    					}
    				}
    			}
    		}
    	}
    	for(int i=0;i<n;i++){
    		for(int j=0;j<m;j++){
    			if(arr[i][j]>=0){
    				cout<<"g";
    			} 
    			else{
    				cout<<".";
    			}
    		}
    		cout<<endl;
    	}
    	return 0;
    }
    

    总结

    本次模拟赛,是在颓废了整整两个月进行的,疫情的原因还没有返校,导致在家是真的堕落,想准备考研被自己的拖延症一直拖一直拖,对于这个模拟赛,就去年参加蓝桥杯省赛B组的经验来看,这次模拟赛的难度和实际比赛差不多,题目类型也一样,很有认真做做的必要,当然是对于我们这些小菜鸡来说哈哈哈

发布了1 篇原创文章 · 获赞 2 · 访问量 78

猜你喜欢

转载自blog.csdn.net/weixin_41949657/article/details/104877232