距离蓝桥杯55天
大一双非本科大数据在读
今天对历届真题进行剖析如有不足请批评指正
题目都可以在蓝桥杯官网找到并提交测评~
真题训练1:日期类题目>>考察对datetime模块的使用
日期类题目最重要的就是判断日期的合法性:强大的Python已为我们准备好了强大datetime模块,相比较其他语言,判断日期合法性要简单很多!
一般而言,日期合法性要检查以下几点:year—month—day,year不能以0打头,month和day 对于1~9日期类题目前面常常加上前导0,比如2月3号写成02—03,但是我们真正使用的只有2和3,也就是说还需要去0的操作,其次month∈[1,12],day的范围还要依据month(大月还是小月还是二月),二月这里又涉及到28和29的问题即闰年和平年的问题。
由此可见,判断起来十分复杂。但如果合理的使用datetime模块,便可迎刃而解!
判断日期合法性板子:
def judge(str):#传入字符串形式的日期 try: year= month= day= datetime.date(year,month,day)#如果日期不合法,会执行except下面那条语句,否则返回True except: return False return True
回到题目本身,根据题意给出的3种排列组合,创建permutations函数 然后遍历(19,20)年份限制,循环判断。
容易出错的点:题目给出的3个参数可能相同,但是我们排列的时候把它认为是不同的,所以需要进行去重>>set(),然后再根据关键字排序输出(列表的元素是可迭代序列)
关键字排序输出:比如s=[(1,2,3),(2,2,3),(2,1,4)]
s.sort(key=lambda x:(x[0],x[1],x[2])) 输出s=[(1, 2, 3), (2, 1, 4), (2, 2, 3)]
感谢这位PY大佬对sort的讲解,对关键字排序不懂的可以看这
a=list(input().strip().split('/')) import datetime def judge(str):#判断日期合法性 try: year=int(str[:4]) month=int(str[4:6]) if str[4]!='0' else int(str[5]) day=int(str[6:]) if str[6]!='0' else int(str[7]) if year<1960 or year>2059:return False datetime.date(year,month,day) except: return False return True def permutations(a):#创建组合情况 l=[] l.append([a[0],a[1],a[2]]) l.append([a[2],a[0],a[1]]) l.append([a[2],a[1],a[0]]) return l ans=[] for i in permutations(a): for j in range(19,21): if judge(str(j)+i[0]+i[1]+i[2]): ans.append(str(j)+i[0]+'-'+i[1]+'-'+i[2]) #去重 排序输出 ans=list(set(ans)) ans.sort(key=lambda x:(int(x[:4]),int(x[5:7]),int(x[8:]))) for i in ans: print(i)
真题训练2:>>考察数学推理能力
问题分析:不妨包含这N个整数的最短的等差数列有n项,且公差为d
项数n=(最大的-最小的)/d+1 要使得n最小,最大的和最小的数字已经由题目给定,那么问题转化为求d最大的问题
下面举个例子 2 4 6 10 20(排序好了) 相邻两项的差值分别为2 2 4 10
由于这串数据是从等差数列取得,因此任意差值一定是d的倍数
设每个差值是公差的k倍(k>=1),因此差值可以表示为kd>=d
所以对于例子,我们可以列出d<=2,d<=2,d<=4,d<=10
所以d的一个必要条件:s代表相邻两项差值组成的集合,d<=min(s)
强调,为什么是必要条件而不是充分条件:原因在于当d=min(s),未必能构成等差数列,比如1 3 8 ,d<=2 但d的最大值是1
观察两组数据seq=[2,4,6,10,20] d=[2,2,4,10] dmax=2
seq=[1,3,8] d=[2,5] dmax=1 我们不妨考虑数组d,里面有N个数据,猜测dmax=N个数据的最大公约数(确实是基于猜测,完整的数学证明还请高手指教)
下面问题就转化为求N个数据的最大公约数:
对于求两个数的gcd,我们已经掌握,那么求N个数字的gcd,我们可以采用递归。
求N个数字的gcd(数字存在列表当中)板子:
def gcd(a,b): while b: a,b=b,a%b return a def multi_gcd(array): l = len(array) if l == 1:#基线条件 return array[0] elif l == 2:#基线条件 return gcd(array[0], array[1]) else:#递归 return gcd(multi_gcd(array[:l//2]), multi_gcd(array[l//2:])) #就是假定左半边的和右半边的是可以求出来的,然后一级一级分下去。
n=int(input().strip()) seq=list(map(int,input().strip().split())) seq.sort() def gcd(a,b): while b: a,b=b,a%b return a def multi_gcd(array): l = len(array) if l == 1: return array[0] elif l == 2: return gcd(array[0], array[1]) else: return gcd(multi_gcd(array[:l//2]), multi_gcd(array[l//2:])) if seq[0]==seq[1]: print(len(seq)) else: d=[seq[i]-seq[i-1] for i in range(1,len(seq))] dmax=multi_gcd(d) print(int((max(seq)-min(seq))/dmax)+1)
真题训练3: >>考察几何逻辑(填空压轴)
答案1391
问题分析:我们可以通过数学递推的手段(找规律),读者请务必作图!
要研究n条直线0个圆最多划分的区域,设递归式为a[n][m]:
那么先研究n条直线0个圆的情况a[n][0],由于研究划分最多的区域,因此交点尽可能多。
容易知道,第n条直线与前n-1条直线至多有n-1个交点。因此作图
可发现规律a[n][0]=2+(2+3+4...+n)
然后研究n条直线1个圆的情况a[n][1],由于研究划分最多的区域,因此交点尽可能多。容易知道,1个圆与1条直线至多有2个交点,因此作图
可发现规律a[n][1]=4+(4+5+....n+2)
然后研究n条直线2个圆的情况a[n][2],作图可知
可发现规律a[n][2]=8+(6+7+....n+4)
然后这里容易出错(第一个数字并非是2的指数次幂),找规律一般需要3个以上
同理得a[n][3]=14+(8+...n+6)
观察每种情况的首项,相邻项作差得到2,4,6...可得a[n][m]展开后的首项为m(m+1)+2
后半部的等差数列,首项排列(2,4,6,8...),可得等差数列首项为2(m+1)
等差数列最后一项和第一项始终保持差值n-2,因此
a[n][m]=m(m+1)+2 +[2(m+1)+........2(m+1)+n-2]
可得答案1391
我是小郑 正在奔赴热爱 奔赴山海! 如果喜欢麻烦给个三连~