蓝桥杯专题之枚举篇

题目列表:

2013年:马虎的算式

2014年:啤酒和饮料,奇怪的分式

2015年:加法变乘法

2016年:生日蜡烛,四平方和

2017年:等差素数列

2019年:数的分解

2020年:既约分数

2021年:货物摆放

2022年模拟赛:插头和插板

2022年校内模拟赛第一次:递增三元组

2022年校内模拟赛第二次:特殊的数

1.马虎的算式

    小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。

    有一次,老师出的题目是:36 x 495 = ?

    他却给抄成了:396 x 45 = ?

    但结果却很戏剧性,他的答案竟然是对的!!

    因为 36 * 495 = 396 * 45 = 17820

    类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54

    假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)

    能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?

请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。

满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数

答案直接通过浏览器提交。
注意:只提交一个表示最终统计种类数的数字,不要提交解答过程或其它多余的内容

答案:142 

分析:

五层循环分别代表a,b,c,d,e,每一层循环都要能取到1~9,且5个数各不相同

 正确代码:

#include<iostream>
using namespace std;
int main(){
	int ans = 0;
	for(int a = 1;a < 10;a++){
		for(int b = 1;b < 10;b++){
			if(b==a) continue;
			for(int c = 1;c < 10;c++){
				if(c==a || c==b) continue;
				for(int d = 1;d < 10;d++){
					if(d==a||d==b||d==c) continue;
					for(int e = 1;e < 10;e++){
						if(e==a||e==b||e==c||e==d) continue;
						if((a*10+b)*(c*100+d*10+e) == (a*100+d*10+b)*(c*10+e)){
							ans++;
						}
					}
				}
			} 
		}
	}
	cout << ans;
	return 0;
}

2.啤酒和饮料

啤酒每罐2.3元,饮料每罐1.9元。小明买了若干啤酒和饮料,一共花了82.3元。

我们还知道他买的啤酒比饮料的数量少,请你计算他买了几罐啤酒。

注意:答案是一个整数。请通过浏览器提交答案。 不要书写任何多余的内容(例如:写了饮料的数量,添加说明文字等)。

答案:11

分析:

为了保证啤酒数量比饮料数量少,我们就可以让他们永远是一个递增的顺序(设j=i+1)

代码:

#include<iostream>
using namespace std;
int main(){
	for(int i = 0;i < 42;i++){
		for(int j = i+1;j < 43;j++){
			if(i*2.3+j*1.9==82.3){
				cout << i;
				break;
			}
		}
	}
	return 0;
}

3.奇怪的分式

上小学的时候,小明经常自己发明新算法。一次,老师出的题目是:1/4 乘以 8/5 ,小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45 (参见下图)

老师刚想批评他,转念一想,这个答案凑巧也对啊,真是见鬼!对于分子、分母都是 1~9 中的一位数的情况,还有哪些算式可以这样计算呢?请写出所有不同算式的个数(包括题中举例的)。显然,交换分子分母后,例如:4/1 乘以 5/8 是满足要求的,这算做不同的算式。但对于分子分母相同的情况,2/2 乘以 3/3 这样的类型太多了,不在计数之列!

注意:答案是个整数(考虑对称性,肯定是偶数)。请通过浏览器提交

答案:14 

分析:

1.除法可能会产生精度问题,所以能转换为乘法的尽量用乘法来做

2.仅有两个数的分子分母都相同时才不在计数之列,如果仅有一个数的分子分母相同时是算在计数之列的,请注意读题!!!

代码:

#include<iostream>
using namespace std;
int main(){
	int ans = 0;
	for(int a = 1;a < 10;a++){
		for(int b = 1;b < 10;b++){
			for(int c = 1;c < 10;c++){
				for(int d = 1;d < 10;d++){
					if(a!=b && c!=d && a*c*(b*10+d) == b*d*(a*10+c)){
						ans++;
					}
				}
			}
		} 
	} 
	cout << ans;
	return 0;
}

5.加法变乘法

我们都知道:1+2+3+ ... + 49 = 1225
现在要求你把其中两个不相邻的加号变成乘号,使得结果为2015

比如:
1+2+3+...+10*11+12+...+27*28+29+...+49 = 2015
就是符合要求的答案。

请你寻找另外一个可能的答案,并把位置靠前的那个乘号左边的数字提交(对于示例,就是提交10)。

注意:需要你提交的是一个整数,不要填写任何多余的内容。

答案:16

分析:

1.枚举两个乘号的位置

2.已知1+2+3+……+49=1225,有两个地方被换上了乘号

a1+b1===>a1*b1

a2+b2===>a2*b2

除了这两块地方,其他地方一模一样,所以2015-1225的差值就是这两组数的替换所产生的差值(题目给的条件永远不是白给的!!)

代码: 

#include<iostream>
using namespace std;
int main(){
	int sum = 0;
	for(int i = 1;i <= 47;i++){//枚举第一个乘号的位置 
		for(int j = i+1;j <= 48;j++){//枚举第二个乘号的位置 
			if(i*(i+1)+j*(j+1)-i-(i+1)-j-(j+1) == 2015-1225){
				cout << i << endl;
			}
		} 
	}
	return 0;
}

6.生日蜡烛

某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的 请填写他开始过生日party的年龄数

答案:26

代码: 

#include<iostream>
using namespace std;
int main(){
	for(int i = 1;;i++){//枚举开始过生日的年龄 
		int j = i;
		int sum = 0;
		while(sum+j<=236){
			sum+=j;
			j++;
			if(sum==236){
				cout << i;
				return 0;
			}
		} 
	}
}

7.四平方和

题目描述

四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。

比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)

对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开

例如,输入:
5
则程序应该输出:
0 0 1 2

再例如,输入:
12
则程序应该输出:
0 2 2 2

再例如,输入:
773535
则程序应该输出:
1 1 267 838

分析:

确定每个数的范围

        a的最小值是0,最大值是n/4,只有在a=b=c=d时,a才会产生最大值

        b的最小值是0,最大值是n/3-i*i,因为假设a=0,只有b=c=d时,b才会产生最大值,且之前a的值已经确定,所以可以减去a^{2}

        c的最小值是0,最大值是n/2-i*I-j*j,同理

        a,b,c都已经确定好了,为了减少时间复杂度,我们可以减少一层循环,只用4层循环来完成。让d=\sqrt{n-a*a-b*b-c*c},看是否a^{2}+b^{2}+c^{2}+d^{2}能够等于n,如果可以就输出

代码: 

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){
	int n;
	cin >> n;
	for(int i = 0;i*i<=n/4;i++){
		for(int j = 0;j*j<=n/3-i*i;j++){
			for(int k = 0;k*k<=n/2-i*i-j*j;k++){
				int l = sqrt(n-i*i-j*j-k*k);
				if(i*i+j*j+k*k+l*l == n){
					cout << i << " " << j << " " << k << " " << l;
					return 0;
				}
			}
		}
	}
}

9.既约分数

如果一个分数的分子和分母的最大公约数是1,这个分数称为既约分数。
例如,4/3 , 5/2 ,1/8 ,7/1都是既约分数。
请问,有多少个既约分数,分子和分母都是1到2020之间的整数(包括1 和2020)?

答案:2481215

代码: 

#include<iostream>
using namespace std;
int gcd(int a,int b){
	return b? gcd(b,a%b) : a;
}
int main(){
	int ans = 0;
	for(int i = 1;i <= 2020;i++){
		for(int j = 1;j <= 2020;j++){
			if(gcd(i,j) == 1){
				ans++;
			}
		}
	}
	cout << ans;
	return 0;
}

10.货物摆放

小蓝有一个超大的仓库,可以摆放很多货物。

现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。

小蓝希望所有的货物最终摆成一个大的长方体。即在长、宽、高的方向上分别堆 L、W、H 的货物,满足 n = L×W×H。

给定 n,请问有多少种堆放货物的方案满足要求。

例如,当 n = 4 时,有以下 6种方案:1×1×4、1×2×2、1×4×1、2×1×2、2 × 2 × 1、4 × 1 × 1

请问,当 n = 2021041820210418(注意有 16 位数字)时,总共有多少种方案?

答案:2430 

分析:

将2021041820210418所有的因子找出,让L,M,H分别从这些因子里选,符合L*M*H==2021041820210418的算一种

代码:

#include<iostream>
using namespace std;
long long a[10000];
int main(){
	long long n = 2021041820210418;
	int k = 0;
	for(long long i = 1;i*i<=n;i++){//注意这里的i要设为long long 类型,因为i*i的范围已经超出了int类型,是无法得出结果的 
		if(n%i==0){
			a[++k] = i;
			if(i!=n/i){
				a[++k] = n/i;
			}
		}
	}
	long long ans = 0;
	for(int l = 1;l <= k;l++){
		for(int w = 1;w <= k;w++){
			for(int h = 1;h <= k;h++){
				if(a[l]*a[w]*a[h] == n){
					ans++;
				}
			} 
		}
	}
	cout << ans;
	return 0;
}

11.插头和插板

问题描述

  小蓝有一个插板,形状用一个 n * m 的01矩阵表示,0 表示板面,1 表示插孔。
  小蓝还有一个插头,形状用一个 r * c 的01矩阵表示,0 表示没有伸出的部分,1 表示伸出的部分。插头伸出的部分必须插在插孔里面。
  为了安全,插头插到面板上不能有任何部分超过插板边界(包括没有伸出的部分)。
  插头和插板都不能旋转,也不能翻转。请求出插头插入插板的合理位置。

输入格式

  输入的第一行包含两个整数 n, m。
  接下来 n 行,每行一个长度为 m 的01串,表示插板的形状。
  接下来一行包含两个整数 r, c。
  接下来 r 行,每行一个长度为 c 的01串,表示插头的形状。

输出格式

  如果插头没办法安全插入插板中,输出“NO”。否则输出两个数 a, b,表示插头的第 1 行第 1 列对应插板的第 a 行第 b 列。如果有多种情况满足要求,输出 a 最小的方案,如果 a 最小的方案有多个,输出在 a 最小的前提下 b 最小的方案。

样例输入

3 4
0110
0000
0000
3 3
000
010
000

样例输出

NO

样例说明

  在插头不超出范围的前提下无法插入。

样例输入

4 7
1110100
1101111
0001111
0000011
2 3
111
011

样例输出

2 4

评测用例规模与约定

  对于 50% 的评测用例,2 <= n, m, r, c <= 20。
  对于所有评测用例,2 <= n, m, r, c <= 100。

分析:

1.枚举插头的起始位置(注意插头不能超过插座),这样的好处是得到的答案一定是a最小,b最小的

2.将插头和插座一一对应,要保证插头上是‘1’的,插座上相对应的位置也是'1',如果不能相对应就返回false

代码: 

#include<iostream>
using namespace std;
const int N = 110;
	int n,m,r,c;
char A[N][N],B[N][N];
bool check(int a,int b){
	for(int i = 0;i < r;i++){
		for(int j = 0;j < c;j++){
			if(B[i][j] == '1' && A[a+i][b+j] == '0'){
				return false;
			}
		} 
	}
	return true; 
}
int main(){
	cin >> n >> m;
	for(int i = 0;i < n;i++){
		cin >> A[i];
	}
	cin >> r >> c;
	for(int i = 0;i < r;i++){
		cin >> B[i];
	}
    //枚举插头的起始位置
	for(int a = 0;a+r <= n;a++){
		for(int b = 0;b+c <= m;b++){
			if(check(a,b)){
				cout << a+1 << " " << b+1;//注意题目是从第1行,第一列开始的
				return 0;
			}
		}
	}
	cout << "NO";
	return 0;
}

12.递增三元组

在数列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]为递增三元组。
请问对于下面的长度为20的数列,有多少个递增三元组?
2,9,17,4,14,10,25,26,11,14,16,17,14,21,16,27,32,20,26,36。

答案:565

代码:

#include<iostream>
using namespace std;
int a[] = {2,9,17,4,14,10,25,26,11,14,16,17,14,21,16,27,32,20,26,36}; 
int main(){
	int ans = 0;
	for(int i = 0;i < 20;i++){
		for(int j = i+1;j < 20;j++){
			for(int k = j+1;k < 20;k++){
				if(a[i] < a[j] && a[j] < a[k]){
					ans++;
				}
			}
		}
	}
	cout << ans;
	return 0;
}

13.特殊的数

2021 是一个非常特殊的数,它可以表示成两个非负整数的平方差,2021 = 45 * 45 - 2 * 2。
2025 也是同样特殊的数,它可以表示成 2025 = 45 * 45 - 0 * 0。
请问,在 1 到 2021 中有多少个这样的数?
请注意,有的数有多种表示方法,例如 9 = 3 * 3 - 0 * 0 = 5 * 5 - 4 * 4,在算答案时只算一次。

答案:1516

分析:

n = a*a-b*b

b的范围是(0,a)

a的范围是[1,n],为什么a至多能取到n呢?

        以n=9为例:假设a=9,为了让a*a-b*b=9,就算b取最大值8,9*9-8*8仍然远大于9,所以a永远不会超过n(1例外)

正确代码:

#include<iostream>
using namespace std;
bool check(int i){
	for(int a = 1;a<=i;a++){
			for(int b = 0;b < a;b++){
				if(a*a-b*b==i){
					return true;
				}
			}
	}
	return false;
}
int main(){
	int ans = 0;
	for(int i = 1;i <= 2021;i++){
		if(check(i)){
			ans++;
		}
	}
	cout << ans;
	return 0;
}

14.数的分解

把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?

注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和 1001+1000+18 被视为同一种。

答案:40785

分析:

1.3个整数各不相同,既然18+1000+1001和1000+1001+18和1001+1000+18视为一种方法,不如我们就按照三个数递增的顺序来

2.既然我们按照递增的顺序,那么被分解的第一个数一定小于\frac{2019}{3},第二个数一定小于2*\frac{2019}{3}

代码:

#include<iostream>
using namespace std;
bool check(int x){ 
	while(x){
		if(x%10 == 2 || x%10 == 4){
			return false;
		}
		x/=10;
	}
	return true;
}
int main(){
	int ans = 0;
	for(int i = 1;i < 673;i++){
		if(!check(i)) continue;
		for(int j = i+1;j < 1346;j++){
			if(!check(j)) continue;
			int k = 2019-i-j;
			if(k > j && check(k)){
				ans++;
			}
		}
	}
	cout << ans;
	return 0;
}

15.等差素数列

等差素数列 2,3,5,7,11,13,....是素数序列。 类似:7,37,67,97,127,157 这样完全由素数组成的等差数列,叫等差素数数列。

上边的数列公差为 30,长度为 6。 2004 年,格林与华人陶哲轩合作证明了:存在任意长度的素数等差数列。 这是数论领域一项惊人的成果! 有这一理论为基础,请你借助手中的计算机,满怀信心地搜索: 长度为 10 的等差素数列,其公差最小值是多少? 

答案:210

分析:

第一层循环枚举公差,第二层循环枚举首项(首项是素数),然后判断该首项和公差的数列的长度能不能达到10,如果能,直接输出公差

代码: 

#include<iostream>
using namespace std;
bool isPrime(int x){
	for(int i = 2;i*i<=x;i++){
		if(x%i==0){
			return false;
		}
	}
	return true;
}
int main(){
	for(int d = 1;;d++){//枚举公差 
		for(int i = 2;i < 10000;i++){//枚举素数 
			if(isPrime(i)){
				int j = i;
				int len = 1;
				while(isPrime(j+d)){
					j += d;
					len++;
					if(len == 10){
						cout << d;
						return 0;
					}
				}
			} 
		} 
	}
} 

  • 6
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
蓝桥杯中常用的枚举法有两种:排列型枚举和组合型枚举。其中,排列型枚举是指从n个元素中取m个元素进行排列,而组合型枚举是指从n个元素中取m个元素进行组合。下面以一个例子来介绍排列型枚举的实现方法。 假设有n个元素,需要从中选出m个元素进行排列,可以使用递归的方式实现。具体实现方法如下: ```python import numpy as np chosen = [] # 存储已选元素 n = 0 # 元素总数 m = 0 # 需要选出的元素个数 def calc(x): """ 递归函数,从第x个元素开始选取 """ if len(chosen) > m: # 已选元素个数超过m个,返回 return if len(chosen) + n - x + 1 < m: # 剩余元素个数不足m个,返回 return if x == n + 1: # 已经选完n个元素,输出结果 for i in chosen: print(i, end=' ') print(' ') return chosen.append(x) # 选取第x个元素 calc(x + 1) # 递归选取下一个元素 chosen.pop() # 不选第x个元素 calc(x + 1) # 递归选取下一个元素 if __name__ == '__main__': tem = input().split() n = int(tem[0]) m = int(tem[1]) calc(1) # 从第1个元素开始选取 ``` 以上代码实现了从n个元素中选取m个元素进行排列的功能,其中chosen列表存储已选元素,calc函数为递归函数,从第x个元素开始选取,如果已选元素个数超过m个或剩余元素个数不足m个,则返回;如果已经选完n个元素,则输出结果;否则,选取第x个元素或不选第x个元素,递归选取下一个元素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值