目录

前言

一、选择题

1.题目描述

2.参考答案

二、编程题

1.比较大小

题目描述

题目解析

AC代码

2.分成整数

题目描述

题目解析

AC代码1(模拟)

AC代码2(dfs)

3.组合

题目描述

题目解析

AC代码1(数论)

AC代码2(Sylvester定理)

4.最大值

题目描述

题目解析

AC代码1(模拟)

AC代码2(二分查找)

5.农作物

题目描述

题目解析

AC代码

6.面积

题目描述

题目解析

AC代码1

AC代码2

前言

        就在前两天,我参与了第十三届蓝桥杯省赛(2022年4月17日)C++中级组,考题挺难,但发挥较好。这是一篇相关的题解,题是我在考试时电脑截屏下来的。

一、选择题

1.题目描述

1.二进制数1101111转换为十六进制是(   ) 

A、157       B、111    C、6f        D、3f

2.下列指针的用法中,不正确的一项是(   ) 

A、int i; int *p=&i;  

B、int i; int *p; i=*p;     

C、int *p; p=0;     

D、int i=5; int *p; p=&i; 

3.以下对main()函数描述正确的一项是(   )  

A、main()函数必须写在所有函数的前面                       

B、main()函数必须写在所有函数的后面                                   

C、main()函数可以写在任何位置,但不能放到其它函数的里面                           

D、main()函数必须固定位置

4.下列函数中不能重载的一项是(   ) 

A、构造函数      B、析构函数      C、成员函数      D、非成员函数

5.定义char a; float b; double c; 执行语句 c=a+b+c 后c的变量类型是(  )。 

A、char         B、float     C、double    D、int

2.参考答案

CBCBC

(1) 四位截断, (110)2=(6)16 , (1111)2=(f)16 ,

(2) *p是一个空地址, 无法引用, B选项错误; C选项属于危险语法, 因为地址0是一个未知地址

(3) main()函数可以写在其它函数后面或前面(声明即可), 其它函数也可以调用main()函数,

main()函数显然无法“放到”其它函数里面, 任何函数都做不到, 文字游戏, 有点无聊。

(4) 析构函数只有一个,无法构成重载。

(5) 已经定义了c是double, 任何运算都不会改变数据的类型, 类型覆盖只会影响运算的结果。

顺便说下类型覆盖, 浮点型>整型>字符型, 布尔型与字符型运算后结果为整型。

二、编程题

1.比较大小

题目描述

        给定两个正整数N和M (0<N<200, 0<M<200, N≠M), 比较两个正整数的大小,然后将较大的一个正整数输出。例如:N=145, M=100, 比较后145大于100, 故输出145.

        样例输入:

        145 100

        样例输出:

        145

题目解析

        很简单,这里用到了max函数,注意用algorithm头文件。

AC代码

#include<iostream>//调用输入输出流头文件
#include<algorithm>//调用算法头文件
using namespace std;//使用标准名字空间
int main(){//主函数开始
	int m,n;//定义整数类型变量m,n
	cin>>m>>n;//输入m,n的值
	cout<<max(m,n);//输出m,n的最大值
    return 0;//主函数结束,返回0
}

2.分成整数

题目描述

        给定一个正整数N,然后将N分解成3个正整数之和,计算出共有多少种符合要求的分解方法.要求:

        1) 分解的3个正整数各不相同;

        2) 分解的三个正整数中都不含数字3和7.

        如:N为8, 可分解为(1,1,6), (1,2,5), (1,3,4), (2,2,4), (2,3,3),

        其中满足要求的分解方法有1种,为(1,2,5) .

        输入描述:

        输入一个正整数N(5<N<501), 表示要分解的正整数

        输出描述:

        输出一个整数,表示共有多少种符合要求的分解方法.

        样例输入:

        8

        样例输出:

        1

题目解析

        把这个题看成两部分:1.将输入的正整数拆分成三个不相同的正整数的和;2.判断这三个整数是否含有数字3或7。

        第一部分可通过枚举实现将三个数设为i,j,n-i-j,保证依次增大,则枚举i即可完成枚举。第二部分可通过子函数来判断。

        同时,也可以用深度搜索Dfs解决问题。

AC代码1(模拟)

#include<iostream>//调用输入输出流头文件
using namespace std;//使用标准名字空间
bool n37(int n){//子函数,用来判断参数是否含有数字3或7 
	while(n){
		if(n%10==3 or n%10==7) return 1;//如果个位为3或7,返回1 
		n/=10;//删除个位 
	}
	return 0;//如果各位都没有3或7,返回0 
}
int main(){//主函数开始
	int n,cnt=0;//定义整数类型变量n,cnt并初始化赋值为0
	cin>>n;//输入n的值
	for(int i=1;i<=n/3-1;i++){//i为三数中最小,至多为n/3-1 
		if(n37(i)) continue;//如果i含有3或7,跳出本次循环,枚举下一个i 
		for(int j=i+1;j<=n/2;j++){//j为三数中第二小,至多为n/2,保证大于i 
			if(n37(j)) continue;//如果j含有3或7,跳出本次循环,枚举下一个j
			if(n37(n-i-j)) continue;//如果n-i-j含有3或7,跳出本次循环,枚举下一个j
			if(n-i-j>j) cnt++;//走到这一步,则三个正整数一定都不含3或7,只需保证n-i-j>j,则拆分符合条件 
		}
	}
	cout<<cnt;//输出cnt的值
    return 0;//主函数结束,返回0
}

AC代码2(dfs)

#include<iostream>//调用输入输出流头文件
using namespace std;//使用标准名字空间
int cnt;//定义整数类型变量cnt
bool ex_37(int n){//判断37; 
	while(n){
		if(n%10==3 || n%10==7) return 0;//若n包含3或7, 返回 0
		n/=10;//查看下一位
	}
	return 1;//否则返回 1 
}
void dfs(int n,int k,int a){//将 n拆成 k份, 至少拆 a 
	if(k==1){ 	//已拆完 
		if(n>=a) cnt+=ex_37(n);//能拆时,判断n是否含有37
		return;//返回
	}
	for(int i=a;i*k<=n;i++) //继续拆 
		if(ex_37(i))//如果没有37
			dfs(n-i,k-1,i+1);//递归
}
int main(){//主函数开始
	int n;//定义整数类型变量
	cin>>n;//输入n的值
	dfs(n,3,1);//深搜
	cout<<cnt<<endl;//输出cnt
	return 0;//主函数结束,返回0
}

3.组合

题目描述

        提示信息

        因数: 整数a除以整数b, (B≠0)的商正好是整数而没有余数,我们就说b是a的因数。

        公因数: 给定若干个整数,如果有一个(些) 数是他们共同的因数,那么这个(些)数就叫做它们的公因数。

        互质数: 公因数只有1的两个非零自然数叫做互质数.

        例如: 2和3的公因数只有1,为互质数。

        某商店将一种糖果, 按照数量打包成N和M两种规格来售卖(N和M维护质数, 且N和M有无数包)这样的售卖方式会限制一些数量的糖果,不能买到。那么在给出N和M的值,请你计算出最多不能买到的糖果数量。

        输入描述:

        输入两个正整数M, (2<N<M<100, N和M为互质数), 表示这两种规格的糖果数量, 正整数之间用一个空格隔开.

        输出描述:

        输出一个整数,表示最多不能买到的糖果数量.

        样例输入:

        2 3

        样例输出:

        1

题目解析

        法一:这个题其实是数学题,容易证明:如果m,n互质,对于所有大于m×n的数,都可以表示成am+bn的形式,其中a,b均为整数,所以我们要找的数在1~m×n-1之间。(数学中进一步可得该数即为m×n-m-n)。
        所以我们可以让i从从m×n-1开始向下枚举,如果i为m的倍数,则该数能表示,然后检查i-1;若不为m的倍数,则减去n,再检查,重复上述过程,直到i小于0,若均不能表示,则i即为我们要找的最大值。

        法二:由 "Sylvester定理" 可知, 对互质整数对(a,b) :

        当 n > ab-a-b 时, ax + by = n 恒有非负整数解;

        当 n = ab-a-b 时, ax + by = n  无 非负整数解;

具体证明icon-default.png?t=M3C8https://zhuanlan.zhihu.com/p/109860246

AC代码1(数论)

#include<iostream>//调用输入输出流头文件
using namespace std;//使用标准名字空间
int main(){//主函数开始
	int n,m;//定义整数类型变量n,m
	cin>>n>>m;//输入n,m的值
	int i=m*n-1;//i从m*n-1开始向下枚举 
	while(1){//装死循环
		int j=i,flag=1;//用j代替i来枚举,因为过程中需要j不停自减,立个flag 
		while(j>=0){//当j还为正整数时,继续检查j 
			if(j%n==0) {flag=0;break;}//如果j是n的倍数,则一定能表示出来,flag倒下,跳出循环 
			j-=m;//如果j不是n的倍数,减掉一个m后继续检查 
		}
		if(flag==1) break;//如果flag还在,说明j一直不能被表示,跳出循环 
		i--;//如果flag倒了,则说明j能被表示,i--,检查下一个数,继续循环 
	}
	cout<<i;//输出i的值
    return 0;
}

AC代码2(Sylvester定理)

#include<iostream>//调用输入输出流头文件
using namespace std;//使用标准名字空间
int main(){//主函数开始
	int n,m;//定义整数类型变量n,m
	cin>>n>>m;//输入n,m的值
	cout<<n*m-n-m<<endl;//输出n*m-n-m的值并换行
	return 0;//主函数结束,返回0
}

4.最大值

题目描述

        手工课上, 老师拿出N张长方形彩纸, 且每张彩纸上都画着W*H的网格(网格铺满整张彩纸).现在老师将N张彩纸裁剪出K张大小相同的正方形, 并且要使才剪出的正方形的边长最大(裁剪的正方形边长必须为整数).

        例如: N=2, 有2张彩纸,第一张彩纸W=4,H=3, 第二张彩纸W=5,H=4, K=6, 裁剪的6个正方形边长最大是2.

        当给出N张长方形彩纸W和H, 及K的值, 请计算出将N张彩纸裁剪出K张大小相同的正方形,正方形的边长最大是多少(裁剪的正方形边长必须为整数).

        输入描述:

        输入分为N+1行, 第一行为正整数N(1<N<500), 表示彩纸数量;

        以下n行每行有两个正整数W和H, 表示每张彩纸的宽和高, 整数之间用一个空格隔开;

        最后一行为正整数K(1<K<500), 表示要剪成的正方形数.

        输出描述:

        输出一个整数,表示正方形的边长最大是多少.

        样例输入:

        2
        4 3
        5 4
        6

        样例输出:

        2

题目解析

        法一:按照要求,我们要尝试剪出最大的正方形,通过各长方形长÷边长×各边÷边长,得到该正方形能剪出几个,再将这个个数与输入的k进行对比,如果够了,则直接输出此时的边长,如果不够,则边长--,再尝试。最开始的边长可以很大,防止不够用,所以我们直接选择所有长宽中的最大值(这个数是一定不行的,但从这个数开始算算的比较快且不会漏答案)。

        法二:"二分答案"

        已知正方形个数 k, 求最大边长 a, 比较麻烦;

        反之, 若已知边长 a, 求能切出的正方形个数 k, 则较容易。

        故不妨尝试所有可能的 a, 看对应的 k能否满足要求。

        一个个尝试又有点慢, 可以对答案进行二分查找。  

AC代码1(模拟)

#include<iostream>//调用输入输出流头文件
#include<algorithm>//调用算法头文件
using namespace std;//使用标准名字空间
int main(){//主函数开始
	int n,k;int a[500],b[500]; //数组a,b分别用来存储长和宽 
	cin>>n;//输入n的值
	for(int i=0;i<n;i++)//for循环,计数器i从0自增到n-1,共循环n次
		cin>>a[i]>>b[i];//输入n个长方形的长和宽 
	cin>>k;//输入k的值
	int big=max(*max_element(a,a+n),*max_element(b,b+n));//找到所有长宽中的最大值 
	while(1){//装死循环
		int sum=0;//sum用来存储所有正方形中能剪出的正方形个数 
		for(int i=0;i<n;i++)
			sum+=(a[i]/big)*(b[i]/big);//对于每一个要剪出的正方形,每张纸能剪出的个数即为该算式 
		if(sum>=k) break;//如果正方形个数够了,跳出循环 
		big--;//big自减1
	}
	cout<<big;//输出此时的边长 
    return 0;//主函数结束,返回0
}

AC代码2(二分查找)

#include<iostream>//调用输入输出流头文件
using namespace std;//使用标准名字空间
int n,k,w[509],h[509];//定义整数类型n,k,w[509],h[509]
bool check(int a){//判断: 切边长为 a的小正方形能否凑够 k个 
	int cnt=0;//定义计数器cnt
	for(int i=0;i<n;++i)//for循环,计数器i从0自增到n-1,共循环n次
		cnt+=(w[i]/a)*(h[i]/a);	//就硬切, 然后硬加 
	return (cnt>=k); //返回cnt是否大于k
}
int main(){//主函数开始
	cin>>n;//输入n的值
	for(int i=0;i<n;++i)//for循环,计数器i从0自增到n-1,共循环n次
		cin>>w[i]>>h[i];//w和 h的顺序其实也无所谓, 摊手 
	cin>>k;//输入k的值
	int L=1, R=*max_element(w,w+n)+1;//随便搞个上下限, 无脑二分:
	while(L+1<R){//当L+1小于R
		int mid=(L+R)/2;//往中间猜 
		if(check(mid)) L=mid;//猜对-->边长小了-->提高下限 
		else R=mid;//猜错-->边长大了-->降低上限
	}
	cout<<L<<endl;//输出L的值
	return 0;//主函数结束,返回0
}

5.农作物

题目描述

        有一块农田被划分为N*M块, 农作物和杂草分布生长在农田中, 其中农作物使用大写字母“R”表示,杂草使用大写字母“X”表示. 请计算出农田中有几块独立的农作物区域(独立的农作物区域指该区域上下左右都被杂草围住, 且N*M以外的区域都是杂草).

        例如: N=4,M=4, 4*4的农田中, 农作物和杂草分布如下图:

        这块4*4的农田中有3块独立的农作物区域(红色的三部分).

        输入描述:

        输入分为n+1行, 第一行为两个正整数n和m (1<n<500, 1<m<500), 表示农田的长和宽, 数字间用一个空格隔开;

        以下n行每行有m个大写字母, 表示每格为农作物或杂草.

        输出描述:

        输出一个整数,表示农田中有几块独立的农作物区域.

        样例输入:

        4 4

        RRRX

        RXRX

        XXXR

        RXXX

        样例输出:

        3

题目解析

        这一道题运用了dfs的解题方法,依次搜索即可,其中标记思想也是很重要的,比较复杂。

AC代码

#include<iostream>//调用输入输出流头文件
using namespace std;//使用标准名字空间
char farm[509][509];//土地 farm: R代表农田, X代表杂草  
int sign[509][509];//状态 sign: 0代表未知, 1代表已知农田, -1代表已知杂草
void dfs(int i,int j){//记录所有相邻的农田  
	if(sign[i][j]) return;//搜过了 
	if(farm[i][j]=='X')//如果有杂草
		sign[i][j]=-1;//记住杂草 
	else{//否则
		sign[i][j]=1;//记住农田, 看看周围有无农田 
		dfs(i-1,j);//上
		dfs(i+1,j);//下
		dfs(i,j-1);//左
		dfs(i,j+1);//右
	}
}
int main() {//主函数结束,返回0
	int n,m,cnt;//定义整数类型变量n,m,cnt
	cin>>n>>m;//输入n,m的值
	for(int i=1;i<=n;++i)//for循环,计数器i从1自增到n,共循环n次
		for(int j=1;j<=m;++j)//for循环,计数器j从1自增到m,共循环m次
			cin>>farm[i][j];//缓冲带: 用杂草把农田围起来 
	for(int i=0;i<=n+1;++i)//for循环,计数器i从0自增到n+1,共循环n+2次
		sign[i][0]=sign[i][m+1]=-1;//记录
	for(int j=0;j<=m+1;++j)//for循环,计数器j从0自增到m+1,共循环m+2次
		sign[0][j]=sign[n+1][j]=-1;//记录
	//开搜	
	for(int i=1;i<=n;++i)//for循环,计数器i从1自增到n,共循环n次
		for(int j=1;j<=m;++j)//for循环,计数器j从1自增到m,共循环m次
			if(!sign[i][j] && farm[i][j]=='R'){//发现了未被记录过的农田 
				cnt++;//cnt自增1
				dfs(i,j);//以此为起点开始搜索 
			}
	cout<<cnt<<endl;//输出cnt的值
	return 0;//主函数结束,返回0
}

6.面积

题目描述

        小蓝要给墙面上的n个矩形区域粉刷涂料, 给出每个矩形左下角和右上角的两个坐标(x1,y1, x2,y2). 请帮助小蓝计算下粉刷涂料的面积是多少, 如果矩形之间有重叠部分只计算一次.

        例如: 有2个矩形,2个矩形左下角和右上角的两个坐标分别为: (2,2,9,5)、(6,1,12,9),

其粉刷涂料的面积是60.

        输入描述:

        先输入n的值;
        再输入分为n行, 每行有四个正整数x1,y1, x2,y2 (1<x1<500, 1<y1<500, 1<x2<500, 1<y2<500,), 表示每个矩形左下角和右上角的两个坐标.

        输出描述:

        输出一个整数,表示粉刷涂料的面积是多少.

        样例输入:

        2

        2 2 9 5

        6 1 12 9

        样例输出:

        60

题目解析

        法一:由于N是不确定的,也就是矩形的数量不确定,在矩形较多的情况下,互相覆盖的情况复杂,不容易用坐标值相减来进行计算。

        于是我们把每个矩形看作是一个点阵。比如一个3x3的矩形,可以看作有3行3列共9个点组成的二维数组。

        把整个坐标系,看作是一个大的二维数组,xy[0][0]即是坐标系的原点,行号代表x轴的值,列号看成y轴得值,那么每个矩形就是这个二维数组中的一部分。

        因此每输入一个矩形的坐标,就可以根据坐标位置在二维数组中取对应得部分,为这些部分得每个数组元素中赋值为True,代表有面积.

        最终数组中值为False得,说明没有矩形能覆盖到,值为True得说明只有一个矩形覆盖到了。

        最终遍历整个点阵数组中的每个元素,累计有数字的元素个数,即最后的面积。

        法二:二维前缀和容斥原理:

         左上角(a,b),右下角(c,d)的矩形区域总和为: 

        s[c][d]-s[c][b]-s[a][d]+s[a][b]

        把上述过程反过来, 就得到了到二维差分(本题中, 权 c=1):

        m[a][b]+=c;

        m[c][b]-=c;

        m[a][d]-=c;

        m[c][d]+=c;

AC代码1

#include<iostream>//调用输入输出流头文件
using namespace std;//使用标准名字空间
bool xy[110][110];//二维数组,用来组成点阵信息
int ans;//定义整数类型变量ans
int main(){//主函数开始
	int n;//定义整数类型变量
	cin>>n;//输入n的值
	int x1,y1,x2,y2;//定义整数类型变量x1,x2,y1,y2
	for(int i=0;i<n;i++){
		cin>>x1>>y1>>x2>>y2;//循环输入每一个矩形的坐标信息
		for(int j=y1+1;j<=y2;j++)  
			for(int k=x1+1;k<=x2;k++)
				xy[j][k]=1;//记录每个矩形点阵信息
	}	
	for(int j=1;j<=109;j++){//for循环,计数器i从1自增到109,共循环109次
		for(int k=1;k<=109;k++)//for循环,计数器k从1自增到109,共循环109次
			if(xy[j][k]) ans++;//累积数组中为真的个数,即为面积 
	}
	cout<<ans;//输出ans
	return 0;//主函数结束,返回0
}

AC代码2

#include<iostream>//调用输入输出流头文件
using namespace std;//使用标准名字空间
int a[509][509],n;
int main(){//主函数开始
	int x1,y1,x2,y2;//定义整数类型x1,x2,y1,y2
    cin>>n;//输入n的值
    for(int i=0;i<n;i++){//for循环,计数器i从0自增到n-1,共循环n次
        cin>>x1>>y1>>x2>>y2;//输入x1,y1,x2,y2
        a[x1+1][y1+1]++;//a[x1+1][y1+1]自增1
        a[x2+1][y1+1]--;//a[x2+1][y1+1]自减1
        a[x1+1][y2+1]--;//a[x1+1][y2+1]自减1
        a[x2+1][y2+1]++;//a[x2+1][y2+1]自增1
    }
	long long sum=0;//定义长整数类型变量sum并初始化赋值为0
	for(int i=1;i<=20;++i)//for循环,计数器i从1自增到20,共循环20次
		for(int j=1;j<=20;++j){//for循环,计数器j从1自增到20,共循环20次
			a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];//a[i][j]自增a[i-1][j]+a[i][j-1]-a[i-1][j-1]
			//此时 a[i][j]里记录的就是每个点被覆盖的次数 
			if(a[i][j]>0) sum++;//如果a[i][j]>0,sum自增1
		}		
	cout<<sum<<endl;//输出sum的值
	return 0;//主函数结束,返回0
}

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐