大致题意就是玩飞行棋,给出初始位置K(距离终点的距离),然后给出丢了n次骰子。第二行输入n个数,代表骰子的值。 如果骰子的值没用完就到了终点,则需要输出paradox。 否则,最后输出两个数,分别代表飞行棋最终的位置,和回退的次数。(如果当前的骰子点数大于当前位置到终点的距离, 多出来的部分需要回退位置。) 输入: 10 2 6 3 输出示例 1 0 输入: 10 4 6 3 3 3 输出示例 1 2 输入: 6 3 4 2 6 输出示例 paradox
这个题比较简单,主要是注意一下边界条件,因为边界条件测试的时候k可能就是0,这个时候也要输出"paradox",另一个边界条件就是最后一个骰子掷完之后可能到终点,这个时候不能输出"paradox"。
k ,n = [int(i) for i in input().split(' ')]
N = [int(i) for i in input().split(' ')]
res = 0
for id,i in enumerate(N):
if i==k and id!=n-1:
print('paradox')
exit(0)
elif i<=k:
k-=i
else:
k=i-k
res +=1
print(k, res)
题目大致意思是,如果一个骰子可以通过上下,或者左右,或者前后翻转。如果通过若干次翻转后两个筛子的六个面点数 一样,则可以算作一个类骰子。 然后第一行输入一个整数n,表示有n个骰子。接下来的n行每行六个数,分别代表骰子的上下,左右,前后六个面的数字,然 后要求计算后输出,有多少类骰子,第二行输出每一类的骰子个数,需要降序排列。 示例 1: 输入: 2 1 2 3 4 5 6 1 2 6 5 3 4 输出: 1 2 示例 2: 输入: 3 1 2 3 4 5 6 1 2 6 5 3 4 1 2 3 4 6 5 输出: 2 2 1 示例 3: 输入: 10 2 5 1 3 4 6 5 4 3 2 1 6 1 4 6 2 3 5 1 5 6 3 4 2 6 4 2 1 5 3 3 6 4 5 2 1 1 6 3 4 2 5 5 1 4 2 6 3 6 2 3 1 5 4 5 3 6 1 4 2 输出: 9 2 1 1 1 1 1 1 1 1
这个题算是蛮有趣的一个题目,因为很多人可能连怎么转都没搞清楚。但是这里就不细讲,可以分析一下,相对的面始终是相对的,可以把相对的面捆绑在一起。互换相对的面的时候,它们的侧面顺序是不变的。互换相对的面之后,上下会和左右颠倒,左右互换会和前后颠倒,前后互换会和左右颠倒。
如果三组相对的面的组合一样的时候,一共会产生两种骰子,即正旋和反旋。接下来只需要判断是正旋还是反旋即可。
把六个面中的三组中最小的数拿出来,记为x1,x2,x3,使得上,左,前(正方向)只从这三个数中产生。如果最后都把x1放在最上面,则有两种情况,x2放在最左面,x3放在最前面或者x2和x3反过来。只需要把这两种情况分清即可。
所以先考虑把x1,x2,x3放到正方向,这个时候统计需要交换几次,这里的交换次数直接用比较统计了。然后考虑把x1放到最前面,比较一下需要交换几次,剩下的就是x2和x3的相对位置了,干脆把这个也记为一次序关系。
最后总结出规律,如果这些情况下的交换次数为偶数,则是正旋的,交换次数为奇数,则是反旋的。然后统计两种情况分别有多少。
用示例中的例子就是1,2,3,4,5,6显然是组内正序,不需要交换,组间也是正序。但是1,2,6,5,3,4,组内的逆序为1,组间的逆序为1,正好是一次旋转。
好吧,我承认这种方式可能比较难以理解,但是是我考试的时候想出来的,如果大家有更好的理解,可以交流。
from collections import defaultdict
n = int(input())
res1 = defaultdict(lambda :0)
res2 = defaultdict(lambda :0)
for i in range(n):
cur = [int(i) for i in input().split(' ')]
o = 0
if cur[0] < cur[1]:
o+=1
if cur[2]<cur[3]:
o +=1
if cur[4]<cur[5]:
o+=1
a, b, c = tuple(sorted(cur[:2])), tuple(sorted(cur[2:4])), tuple(sorted(cur[4:]))
if a[0]<b[0] :
o+=1
if a[0]<c[0]:
o+=1
if b[0]<c[0]:
o+=1
if o&1:
res1[tuple(sorted([a,b,c]))]+=1
else:
res2[tuple(sorted([a,b,c]))]+=1
print(len(res1)+len(res2))
for i in list(res1.values())+list(res2.values()), reverse=True):
print(i, end=' ')
题目的大致意思是,一个人每天最多吃两顿饭,早餐和午餐,每餐只能选择一个套餐,每个套餐对应了一个热量值和美味值,这个人吃饭必须得满足两餐的总美味值高于预期,两顿饭都可以不吃。现在要求在满足美味值的条件下,热量值要最小。 输入三个数,m,n,t分别代表中餐套餐数目,晚餐套餐数目和美味值标准。要求输出最小摄入的热量值。如果怎么都达不到美味值,输出-1 示例 1:输入: 5 1 9 9 1 4 9 3 1 2 3 6 5 9 8 输出:4 (解释:只需要吃一顿中餐即可)示例 2: 输入: 1 1 0 3 1 2 1 输出: 0(解释,一顿都不吃)示例 3: 输入: 3 3 10 1 1 2 5 3 7 2 4 4 8 6 9 输出: 5示例 4: 输入: 2 1 4 3 1 2 1 1 2 输出:-1(解释怎么都达不到美味值,输出-1)
思路就是把每个中餐拿出来去和晚餐配对,如果美味值大于预期,则看两者的能量和是否更小。因为晚餐已经是排好序了,我们可以倒序判断美味值是否大于预期。固定住中餐,一旦加上晚餐的美味值低于预期,内层循环立即跳出。
这个题我只过了65,先贴代码。之后又优化外层循环提前退出和优化不对中餐进行排序,优化后代码还是65。
def main():
n,m,t = [int(i) for i in input().split(' ')]
if t ==0:
print(0)
return
res = float('inf')
mid = [[0,0]]
night = [[0,0]]
for _ in range(n):
mid.append([int(i) for i in input().split(' ')])
mid.sort(key=lambda x:x[1])
for _ in range(m):
night.append([int(i) for i in input().split(' ')])
night.sort(key=lambda x:x[1])
print(mid)
print(night)
if mid[-1][1] + night[-1][1] < t:
# 最大的营养值达不到预期
print(-1)
return
for i in range(len(mid)-1, -1, -1):
if mid[i][1] + night[-1][1] < t:
break
for j in range(len(night)-1, -1, -1):
if mid[i][1] + night[j][1] >=t:
res = min(res ,mid[i][0] + night[j][0])
else:
break
print(res)
if __name__ == '__main__':
main()
和过了这个题的人交流,把别人的思路也梳理一下,思想就是排序之后,如果有一个套餐能量比某些套餐能量大,但是美味值还低,这些套餐是一定都不会选的,干脆就把这些套餐剔除。这个思想的弊端在于删除这些套餐的是,需要重新建一个list,然后把不删除的放进list里。否则删除的复杂度也很大,会影响效果。改进后的代码如下。
def deleteSupported(array):
array.sort(key=lambda x:x[1],reverse=True)
newArray = []
pre = float('inf')
for item in array:
if item[0] < pre:
pre = item[0]
newArray.append(item)
return newArray # 注意,这里已经是倒序了,所以后面循环不需要倒序
def main():
n,m,t = [int(i) for i in input().split(' ')]
if t ==0:
print(0)
return
res = float('inf')
mid = [[0,0]]
night = [[0,0]]
for _ in range(n):
mid.append([int(i) for i in input().split(' ')])
mid = deleteSupported(mid)
for _ in range(m):
night.append([int(i) for i in input().split(' ')])
night = deleteSupported(night)
if mid[0][1] + night[0][1] < t:
print(-1)
return
for i in range(len(mid)):
if mid[i][1] + night[0][1] < t:
break
for j in range(len(night)):
if mid[i][1] + night[j][1] >=t:
res = min(res ,mid[i][0] + night[j][0])
else:
break
print(res)
if __name__ == '__main__':
main()
上面的代码已经可以通过(看别人的讨论说的)。既然到这一步,中餐和晚餐已经是排好序的序列了,而且也已经剔除了用不上的一部分套餐。这样还带来了一个好处,那就是如果选定了一个值,这样就不会存在既比当前选定的这个套餐营养值高,且能量低的套餐。所以这个时候,也不用遍历整个数组,直接选定中餐后,晚餐可以二分查找了,因为只需要一个营养值恰好满足目标值的套餐。就是这个中餐对应的最优解。
但是二分查找就是最优的了吗?并不是,现在想想。既然中餐和晚餐都排好序了。中餐的营养值较小者必然对应晚餐营养值较大者,反之亦然。那么是否可以使用双指针,这个时候营养值越小,能量肯定也越小。中餐从小往大遍历,晚餐从大往小遍历,即可找到所有可能为最小值的组合。
def deleteSupported(array):
array.sort(key=lambda x:x[1],reverse=True)
newArray = []
pre = float('inf')
for item in array:
if item[0] < pre:
pre = item[0]
newArray.append(item)
return newArray # 注意,这里已经是倒序了,所以后面循环不需要倒序
def main():
n,m,t = [int(i) for i in input().split(' ')]
if t ==0:
print(0)
return
res = float('inf')
mid = [[0,0]]
night = [[0,0]]
for _ in range(n):
mid.append([int(i) for i in input().split(' ')])
mid = deleteSupported(mid)
for _ in range(m):
night.append([int(i) for i in input().split(' ')])
night = deleteSupported(night)
if mid[0][1] + night[0][1] < t:
print(-1)
return
i, j = len(mid)-1, 0
while j<len(night) and i>=0:
if mid[i][1] + night[j][1] >= t:
res = min(res, mid[i][0] + night[j][0])
j+=1
else:
i -=1
print(res)
关于这个题想写的就这么多了,值得一提的是,有人用上了输入数据小于10W这一条信息,直接用基于counting sort的思想,把这个题的复杂度按到了 O ( n ) O(n) O(n)级别,但是掌握好通用思想就好了。
是一道排列组合题,我自己没理顺,靠技巧过了一些case,后面搞懂了有空再贴。
大致内容就是这样了,如果有瑕疵欢迎大家交流,也感谢大家指出我的错误。