Python解题 - CSDN周赛第17期 - 拯救公主
本期又出现了题目测试数据的问题,而且题目和算法关系也不太大,基本就属于用代码代替手工解答算术题的感觉。不禁让人怀疑官方题库是否已经没有高质量的题了,同时也怀疑长期满分却又不更新博客拿奖品的某位选手是不是托。。。
第一题:判断胜负
已知两个字符串A,B。连续进行读入n次。每次读入的字符串都为A|B。输出读入次数最多的字符串。
分析
这题太简单了,但是问哥想复杂了,审题不严,漏看了题目已经限定了只有两个字符串,还引入了Counter类来生成字典,杀鸡用了牛刀。不过由于输入是字符串,用字典来计数应该是最简便的,只要按照输入顺序分别累加A或B的次数,最后再进行比较输出就好了。唯一要注意的地方就是有可能两个字符串出现的次数一样,这时要输出“dogfall”,表示平手。
参考代码
d = dict()
n = int(input().strip())
for _ in range(n):
s = input().strip()
d[s] = d.get(s,0) + 1
if len(d)>1 and len(set(d.values()))==1:
print("dogfall")
else:
print(max(d.items(),key=lambda x:x[1])[0])
第二题:买铅笔
P老师需要去商店买n支铅笔作为小朋友们参加编程比赛的礼物。她发现商店一共有 3 种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同。为了公平起见,P老师决定只买同一种包装的铅笔。商店不允许将铅笔的包装拆开,因此P老师可能需要购买超过 n 支铅笔才够给小朋友们发礼物。现在P老师想知道,在商店每种包装的数量都足够的情况下,要买够至少 n 支铅笔最少需要花费多少钱。
分析
很久之前做过的题了,也没什么可说的。x、y 分别代表了三种包装每包的铅笔数量和价格,然后用总数 n 除去每种包装的铅笔数量,向上取整(因为拆开就得全买),最后比较一下三种情况里哪种用钱最少即可。
代码也就一句话的事:
参考代码
n = int(input())
arr = [list(map(int, input().strip().split())) for _ in range(3)]
print(min((n//x+bool(n%x))*y for x,y in arr))
第三题:拯救爱情
小艺酱走到一个花之占卜店中。 店员小Q看到小艺酱可怜的样子,允许小艺酱免费占卜一次。 花瓣占卜: 1. 一瓣“在一 起”,一瓣“不在一起”;开始的花瓣表示“在一起”。 2. 直到最后一个花瓣落地游戏结束。 3. 可以选择多朵花,选择撕一朵花就必须撕完。
示例
示例一 示例二 输入 1
1
6
0 8 3 5 7 7
输出 1 27
分析
本期争议最大的题目。除了长期霸榜的某选手(托?),其他人一律只通过70%。
从题面和给出的示例上看,最后答案一定是奇数。做法也有很多种,这里也就不啰嗦了。但让人百思不得其解的就是那30%不通过的数据到底长什么样?
参考代码
n = int(input().strip())
nums = list((map(int, input().strip().split())))
res = 0
odd = []
for i in nums:
if i%2:
odd.append(i)
res += i
if res%2==0:
res -= min(odd)
print(res)
有人说可能是因为没有考虑到最终结果得不到奇数的情况,也就是说给的花瓣数只有偶数。但是很可惜,问哥早就测试过了。对于编译型语言可能无法做这样的测试,但是解释型语言如python很简单就可以判断测试数据里有没有特定的值。比如加个判断语句,当最终结果是偶数的时候,执行一条ValueError的代码,如 int("abc")。由于python是逐行执行,如果代码逻辑执行不到这里,就不会检查出这里的Value错误。而问哥加上这句后,代码还是只通过70%的测试用例,并不报错,说明测试用例里不存在只有偶数的情况。只能等官方解释吧(虽然基本没有)。
第四题:拯救公主
在Flower Kingdom里,住着一位美丽的公主Ana,有一天Ana得了一种怪病,神医告知国王,在遥远的幽谷中有一种药能治愈Ana, 但是神医只有一份不完整的地图,地图的描述如下: 该地图的共有3行,第一行有m列,m为奇数,第二行有m+1列,第三行有m+2列; 每一行用一个字符串表示,只有【两种字符】;‘.'表示草地,可以从它上面通过,‘*’表示岩石,每一行最多一个‘*’;入口在左上角,由于在对角线方向上,因此即使对角线两边都有岩石,但是缝隙较大,人可以通过,故人可以向八个方向行走; 真实地图是由该地图的【每一行无限循环】得到的,这种神奇的药草就生长在第x行第y列的草地上,药草可能会在岩石上;国王决定派遣勇敢的骑士David前去寻找拯救公主的解药;现在聪明的你是否知道David能否找到该药?
第一行输入T,表示测试用例的个数,第二行三个整数 m, x, y,分别代表第一行字符串的长度、草药所在地的行、列。接着三行字符串,然后循环 T 次。
输出YES或NO,针对 T 个用例依次换行输出。
示例:
示例 输入 1
3 1 10
.*.
...*
..*..
输出 NO
分析
字符串题,简单概况来说就是,有三行 n 列不断重复的字符串矩阵(三行各自重复字段长度不同),矩阵中的点(.)代表草地,可以通行,星号(*)代表石头,不能通行,而只要石头不在同一列的位置,就可以斜向通行,每一行的重复字段里最多只有一个星号。问勇敢的骑士能不能到达矩阵中的指定位置。
我们画图来看看,以示例为例:
可以看到,在将每一行的字符串循环拼接后,在第8列的位置,出现了三行都是石头的情况,而草药在第10列,这个时候,勇士就无法到达草药的位置了,所以结果输出NO。
接下来,我们来仔细分析一下本题。首先,题目说了入口在左上角,换句话说,如果第一行字符串的第一个字符是星号(“*”),则不用继续判断,答案就是NO。
其次,题目还说了,草药有可能长在石头上(这不坑人么),如果出现这种情况,也不用再去判断其他行,答案也是NO。
再次,题目还说了,每行重复字符串里的星号(*)最多只出现一次,那也有可能不出现啊,如果有至少一行字符串里没有星号(“*”),而草药所在的位置不是星号(在上一步检查过了),则答案就肯定是YES了,因为如果只有两行有石头的情况下,草药必须是下面这样的位置,勇士才无法找到。而无论哪种位置,都是不可能出现的。(中间行的最小长度是2,不可能出现3个星号连在一起的情况)
如果经过上面的判断,还无法得到答案(不管YES还是NO),我们就需要进行终极判断了——找到那堵“墙”的位置,也就是三行一定存在某个相同的列,都是星号。然后再用这个列的位置和草药所在的列的位置进行对比,如果草药在前(还没遇到“墙”呢),答案就是YES,如果草药在后(比如示例),答案就是NO。
连续三个自然数(m,m+1,m+2)的最小公倍数 p 等于三者之乘积(除非m等于2,但题目说了m是奇数),也就是说,三个字符串不管长什么样,一定在第 p+1 列开始重复之前的样子。于是,我们只要找到星号在每一行的初始位置,然后以 p+1 为上界,以 m/m+1/m+2 为步长,进行枚举,找出三者相同的列数,就等于找到答案了(问哥这里用了集合里求交集的办法)。
参考代码
T = int(input().strip())
res = []
for _ in range(T):
m, x, y = map(int, input().strip().split())
s = [input().strip() for _ in range(3)]
if s[0][0] == "*":
res.append("NO") # 第一种情况,入口即岩石
elif s[x-1][(y-1)%(m+x-1)] == "*":
res.append("NO") # 第二种情况,草药长在石头上
else:
stone = []
for i in s:
temp = i.find("*")
if temp < 0:
res.append("YES") # 第三种情况,有一行没有石头
break
stone.append(temp)
else:
p = m*(m+1)*(m+2)
wall = set(range(stone[0],p,m))&set(range(stone[1],p,m+1))&set(range(stone[2],p,m+2))
if y-1 > wall.pop():
res.append("NO")
else:
res.append("YES")
for i in res:
print(i)