1.
题目描述
今天上课,老师教了小易怎么计算加法和乘法,乘法的优先级大于加法,但是如果一个运算加了括号,那么它的优先级是最高的。例如:
1+2*3=7
1*(2+3)=5
1*2*3=6
(1+2)*3=9
现在小易希望你帮他计算给定3个数a,b,c,在它们中间添加"+", "*", "(", ")"符号,能够获得的最大值。
输入描述:
一行三个数a,b,c (1 <= a, b, c <= 10)
输出描述:
能够获得的最大值
示例1
输入
复制
1 2 3
输出
复制
9
答案:
# 直接将所有情况进行列举,然后打印出最大值。
if __name__ == '__main__':
a, b, c = list(map(int, input().strip().split()))
p = [a + b + c, a * b + c, a * (b + c), b+a*c, (b+a)*c, a + b * c, (a + b) * c, a * b * c]
print(max(p))
2.
题目描述
小易有一些立方体,每个立方体的边长为1,他用这些立方体搭了一些塔。
现在小易定义:这些塔的不稳定值为它们之中最高的塔与最低的塔的高度差。
小易想让这些塔尽量稳定,所以他进行了如下操作:每次从某座塔上取下一块立方体,并把它放到另一座塔上。
注意,小易不会把立方体放到它原本的那座塔上,因为他认为这样毫无意义。
现在小易想要知道,他进行了不超过k次操作之后,不稳定值最小是多少。
输入描述:
第一行两个数n,k (1 <= n <= 100, 0 <= k <= 1000)表示塔的数量以及最多操作的次数。
第二行n个数,ai(1 <= ai <= 104)表示第i座塔的初始高度。
输出描述:
第一行两个数s, m,表示最小的不稳定值和操作次数(m <= k)
接下来m行,每行两个数x,y表示从第x座塔上取下一块立方体放到第y座塔上。
示例1
输入
复制
3 2
5 8 5
输出
复制
0 2
2 1
2 3
解答:
# 这道题的思想直接是每次的转移都是最高塔到最低塔。
import sys
if __name__ == "__main__":
lines = sys.stdin.readlines()
n,k = list(map(int,lines[0].strip().split(" ")))
A = list(map(int,lines[1].strip().split(" ")))
# 结果记录list
res_list = []
num_step = 0
for i in range(k):
if max(A) == min(A):
break
num_step += 1
max_index = A.index(max(A))
min_index = A.index(min(A))
res_list.append([max_index+1, min_index+1])
A[max_index] -= 1
A[min_index] += 1
print("%d %d" % (max(A)-min(A), num_step))
for i in range(len(res_list)):
print("%d %d" % (res_list[i][0], res_list[i][1]))
3.
题目描述
小易在学校中学习了关于字符串的理论, 于是他基于此完成了一个字典的项目。
小易的这个字典很奇特, 字典内的每个单词都包含n个'a'和m个'z', 并且所有单词按照字典序排列。
小易现在希望你能帮他找出第k个单词是什么。
输入描述:
输入包括一行三个整数n, m, k(1 <= n, m <= 100, 1 <= k <= 109), 以空格分割。
输出描述:
输出第k个字典中的字符串,如果无解,输出-1。
示例1
输入
复制
2 2 6
输出
复制
zzaa
说明
字典中的字符串依次为aazz azaz azza zaaz zaza zzaa
解题思路分析:
排列组合,n个'a'和m个'z',只能组成$C_{n+m}^n$,记为count(n+m,n) 个单词。
思路:
- 假设第一个字符为a,则剩下n-1个'a'和m个'z'组成的子序列只能构成count(n-1+m,n-1)个单词,且是字典中前count(n-1+m,n-1)个单词。
- 比较k和count(n-1+m,n-1),若k小,说明k是前count(n-1+m,n-1)个单词,则第一个字符必为'a'。子问题化为在子序列(n-1个'a'和m个'z')找到第k个单词
- 若k大,则说明第一个字符必为'z',单词是以'z'开头的单词中的第k-count(n-1+m,n-1)个。子问题化为在子序列(n个'a'和m-1个'z')找到第k-count(n+m-1,m-1)个单词。
eg:n=2,m=2,k=5
- 假设第一个字符为a,则剩下1个a,2个z只能构成3个单词,且是字典中前3个单词(aamm,amam,amma)
- k>3,则第一个字符必为z。原问题化为在n=2,m=1,k=2,即在剩下2个a,1个z中找到第2个单词
# way second False method 没有考虑所有的情况。
def C(n, m):
ret = 1
for i in range(n + 1, n + m + 1):
ret *= I
for i in range(1, m + 1):
ret //= I
return ret
if __name__ == "__main__":
n, m, k = map(int, input().strip().split(' '))
ans = ""
if C(n, m) < k:
ans += '-1'
else:
while n and m:
temp = C(n - 1, m)
if temp < k:
k -= temp
ans += 'z'
m -= 1
else:
ans += 'a'
n -= 1
ans += 'a' * n #这应该是m=0的情况,应该单独while说明
ans += 'z' * m #这应该是n=0的情况,应该单独while说明
print(ans)
# way third True method
def func(k):
re=1
for i in range(1,k+1):
re*=i
return re
n,m,k= [int(i) for i in input().split()]
re=''
if k>func(n+m)/func(n)/func(m):
print(-1)
exit()
while n!=0 and m!=0:
half=func(n+m-1)/func(n-1)/func(m)
if k>half:
k-=half
re+='z'
m-=1
else:
re+='a'
n-=1
while n!=0:
n-=1
re+='a'
while m!=0:
m-=1
re+='z'
print(re)
4.
题目描述
小明在越南旅游,参加了当地的娱乐活动。小明运气很好,拿到了大奖, 到了最后的拿奖金环节。小明发现桌子上放着一列红包,每个红包上写着奖金数额。
现在主持人给要求小明在这一列红包之间“切”2刀,将这一列红包“切”成3组,并且第一组的奖金之和等于最后一组奖金和(允许任意一组的红包集合是空)。最终第一组红包的奖金之和就是小明能拿到的总奖金。小明想知道最多能拿到的奖金是多少,你能帮他算算吗。
举例解释:桌子上放了红包 1, 2, 3, 4, 7, 10。小明在“4,7”之间、“7,10” 之间各切一刀,将红包分成3组 [1, 2, 3, 4] [7] [10],其中第一组奖金之和=第三组奖金之和=10,所以小明可以拿到10越南盾。
输入描述:
第一行包含一个正整数n,(1<=n<= 200 000),表示有多少个红包。
第二行包含n个正整数d[i],表示每个红包包含的奖金数额。其中1<= d[i] <= 1000 000 000
输出描述:
小明可以拿到的总奖金
示例1
输入
复制
5
1 3 1 1 4
输出
复制
5
说明
[1,3,1] [ ] [1,4] ,其中第一组奖金和是5,等于第三组奖金和。所以小明可以拿到5越南盾
示例2
输入
复制
5
1 3 2 1 4
输出
复制
4
说明
[1,3] [2,1] [4],小明可以拿到4越南盾
示例3
输入
复制
3
4 1 2
输出
复制
0
说明
[ ] [4, 1, 2] [ ] ,小明没办法,为了保证第一组第三组相等,只能都分成空的。所以小明只能拿到0越南盾。
思路:
/*
从左右两端共进。
若当前左端大于右端,右端前进一个。
若当前左端小于右端,左端前进一个。
如当前左端等于右端,左右两端都前进一个。
然后再判断左右两端和是否相等,若相等则更新答案。
左端坐标大于右端坐标时,跳出循环。
O(n)。
def redPacket(n, nums):
left, right = -1, n
sum_left, sum_right = 0, 0
res = 0
while left < right:
if sum_left == sum_right:
res = sum_left
left, right = left+1, right-1
sum_left += nums[left]
sum_right += nums[right]
elif sum_left < sum_right:
left += 1
sum_left += nums[left]
else:
right -= 1
sum_right += nums[right]
return res
if __name__ == '__main__':
n = int(input())
nums = list(map(int, input().split()))
print(redPacket(n, nums))
5. 将满二叉树转换为求和树
题目描述
给满出二叉树,编写算法将其转化为求和树
什么是求和树:二叉树的求和树, 是一颗同样结构的二叉树,其树中的每个节点将包含原始树中的左子树和右子树的和。
二叉树:
10
/ \
-2 6
/ \ / \
8 -4 7 5
求和树:
20(4-2+12+6)
/ \
4(8-4) 12(7+5)
/ \ / \
0 0 0 0
二叉树给出前序和中序输入,求和树要求中序输出;
所有处理数据不会大于int;
输入描述:
2行整数,第1行表示二叉树的前序遍历,第2行表示二叉树的中序遍历,以空格分割
输出描述:
1行整数,表示求和树的中序遍历,以空格分割
示例1
输入
复制
10 -2 8 -4 6 7 5
8 -2 -4 10 7 6 5
输出
复制
0 4 0 20 0 12 0
def func(pre,inorder):
if(len(pre)==1):
return [0]
elif(len(pre)==0):
return []
ind = inorder.index(pre[0])
return func(pre[1:(ind+1)],inorder[0:ind]) + [sum(inorder[:])-inorder[ind]]+func(pre[(ind+1):],inorder[(ind+1):])
# 递归算法求解
pre=list(map(int,input().strip().split())) # 前序遍历结果
inorder=list(map(int,input().strip().split())) # 中序遍历结果
ans = func(pre,inorder)
print(' '.join(map(str,ans)))
6. 搭积木
题目描述
小明有一袋子长方形的积木,如果一个积木A的长和宽都不大于另外一个积木B的长和宽,则积木A可以搭在积木B的上面。好奇的小明特别想知道这一袋子积木最多可以搭多少层,你能帮他想想办法吗?
定义每一个长方形的长L和宽W都为正整数,并且1 <= W <= L <= INT_MAX, 袋子里面长方形的个数为N, 并且 1 <= N <= 1000000.
假如袋子里共有5个积木分别为 (2, 2), (2, 4), (3, 3), (2, 5), (4, 5), 则不难判断这些积木最多可以搭成4层, 因为(2, 2) < (2, 4) < (2, 5) < (4, 5)。
输入描述:
第一行为积木的总个数 N
之后一共有N行,分别对应于每一个积木的宽W和长L
输出描述:
输出总共可以搭的层数
示例1
输入
复制
5
2 2
2 4
3 3
2 5
4 5
输出
复制
4
分析思路: 针对现有的(w,l)序列进行宽的升序排列,然后基于此顺序抽取L的非递减序列。
import bisect
def upper(arr, num):
index = bisect.bisect(arr, num)
arr[index] = num
n = int(input())
arr = []
for _ in range(n):
w, l = map(int, input().strip().split(' '))
arr.append((w,l))
arr.sort(key=lambda x:x[0]) # 首先针对N组数据进行对宽的升序;再在此基础上寻找长的非递减序列
L = []
for w,l in arr:
if not L:
L.append(l)
elif l >= L[-1]:
L.append(l)
else:
upper(L, l)
print(len(L))
7. 魔法深渊 (跳台阶问题)
题目描述
前几个月放映的头号玩家简直火得不能再火了,作为一个探索终极AI的研究人员,月神自然去看了此神剧。
由于太过兴奋,晚上月神做了一个奇怪的梦,月神梦见自己掉入了一个被施放了魔法的深渊,月神想要爬上此深渊。
已知深渊有N层台阶构成(1 <= N <= 1000),并且每次月神仅可往上爬2的整数次幂个台阶(1、2、4、....),请你编程告诉月神,月神有多少种方法爬出深渊
输入描述:
输入共有M行,(1<=M<=1000)
第一行输入一个数M表示有多少组测试数据,
接着有M行,每一行都输入一个N表示深渊的台阶数
输出描述:
输出可能的爬出深渊的方式
示例1
输入
复制
4
1
2
3
4
输出
复制
1
2
3
6
分析
"""
台阶问题考虑动态规划
每次仅可往上爬2的整数次幂个台阶(1、2、4、....)
当前台阶方法数 = 所有一次可到达当前台阶方法数的和
dp[n] = dp[n-1]+dp[n-2]+dp[n-4]+... ( n-t>=0,dp[0]=1 )
"""
if __name__ == '__main__':
m = int(input()) # m个测试数据
stairs = []
for i in range(0,m):
stairs.append(int(input()))
n = max(stairs) # 比N的最大值1000时用1001的时间消耗更小。
dp = [0] * 1001
dp[0] = 1
MOD = 10**9 +3
for i in range(1, n+1):
t = 1
while t <= i:
dp[i] += dp[i-t] # dp[n] = dp[n-1]+dp[n-2]+dp[n-4]+... ( n-t>=0,dp[0]=1 )
dp[i] %= MOD # 为了防止移除,需要对mod进行取模运算
t *= 2
for i in stairs:
print(dp[i])
8. 善变的同伴
题目描述
又到了吃午饭的时间,你和你的同伴刚刚研发出了最新的GSS-483型自动打饭机器人,现在你们正在对机器人进行功能测试。
为了简化问题,我们假设午饭一共有N个菜,对于第i个菜,你和你的同伴对其定义了一个好吃程度(或难吃程度,如果是负数的话……)A[i],
由于一些技(经)术(费)限制,机器人一次只能接受一个指令:两个数L, R——表示机器人将会去打第L~R一共R-L+1个菜。
本着不浪费的原则,你们决定机器人打上来的菜,含着泪也要都吃完,于是你们希望机器人打的菜的好吃程度之和最大
然而,你善变的同伴希望对机器人进行多次测试(实际上可能是为了多吃到好吃的菜),他想知道机器人打M次菜能达到的最大的好吃程度之和
当然,打过一次的菜是不能再打的,而且你也可以对机器人输入-1, -1,表示一个菜也不打
输入描述:
第一行:N, M
第二行:A[1], A[2], ..., A[N]
输出描述:
一个数字S,表示M次打菜的最大好吃程度之和
示例1
输入
复制
7 2
1 2 3 -2 3 -10 3
输出
复制
10
说明
[1 2 3 -2 3] -10 [3]
示例2
输入
复制
7 4
1 2 3 -2 3 -10 3
输出
复制
12
说明
[1 2 3] -2 [3] -10 [3]
第四次给机器人-1, -1的指令
备注:
N <= 10^5 = 100000
|A[i]| <= 10^4 = 10000
10%数据M = 1
50%数据M <= 2
80%数据M <= 100
100%数据M <= 10^4 = 10000
思路:
1、先把整个数组改成正负交错的数组,去掉首尾的负数(相邻的正数合并成一个正数,负数合并成一个负数)
2、如果正数个数<=M,输出所有的正数之和
3、如果正数个数>M,将数组中[正负正]合并,该负数为数组中负数的最大值并且三者之和>三者最大值
4、直到3不满足或者正数个数<=M,输出最大的M个正数之和
N, M = list(map(int, input().split()))
ns = list(map(int, input().split()))
new_ns = [ns[0]]
for i in ns[1:]:
if i == 0:
continue
if (new_ns[-1] > 0) == (i > 0):
new_ns[-1] += i
else:
new_ns.append(i)
# 去掉首尾的负数块
if len(new_ns) >= 1 and new_ns[0] < 0:
new_ns.pop(0)
if len(new_ns) >= 1 and new_ns[-1] < 0:
new_ns.pop(-1)
# 按奇偶划分奇数和偶数块
ns_pos = new_ns[0::2]
ns_neg = new_ns[1::2]
cnt_pos = len(ns_pos)
# 如果 M 的值小于正数块的数量则进行合并
updated = True
while updated and M < cnt_pos:
""""""
updated = False
mx_i = 0
# mx = max(ns_pos[mx_i] + ns_pos[mx_i+1] + ns_neg[mx_i], ns_pos[mx_i], ns_pos[mx_i])
mx = float("-inf")
for i in range(len(ns_neg)):
tmp = ns_pos[i] + ns_pos[i+1] + ns_neg[i]
if tmp < max(ns_pos[i], ns_pos[i+1]): # 如果合并后减小则不合并
continue
if tmp > mx:
updated = True
mx = tmp
mx_i = i
if updated:
# 更新合并后的数组
ns_neg.pop(mx_i)
ns_pos[mx_i] = mx
ns_pos.pop(mx_i+1)
cnt_pos -= 1
ns_pos.sort(reverse=True)
print(sum(ns_pos[:M]))
# 不正确的解答,时间超时。
9. 字符串归一
题目描述
通过键盘输入一串小写字母(a~z)组成的字符串。
请编写一个字符串归一化程序,统计字符串中相同字符出现的次数,并按字典序输出字符及其出现次数。
例如字符串"babcc"归一化后为"a1b2c2"
输入描述:
每个测试用例每行为一个字符串,以'\n'结尾,例如cccddecca
输出描述:
输出压缩后的字符串ac5d2e
示例1
输入
复制
dabcab
输出
复制
a2b2c1d1
分析:注意使用collections下的counter类,更有效率
from collections import Counter
char_list = input()
char_dict = Counter(char_list)
res = ''
for key in sorted(char_dict.keys()):
res += key
res += str(char_dict[key])
print(res)
10. 字符串排序
题目描述
月神拿到一个新的数据集,其中每个样本都是一个字符串(长度小于100),样本的的后六位是纯数字,月神需要将所有样本的后六位数字提出来,转换成数字,并排序输出。
月神要实现这样一个很简单的功能确没有时间,作为好朋友的你,一定能解决月神的烦恼,对吧。
输入描述:
每个测试用例的第一行是一个正整数M(1<=M<=100),表示数据集的样本数目
接下来输入M行,每行是数据集的一个样本,每个样本均是字符串,且后六位是数字字符。
输出描述:
对每个数据集,输出所有样本的后六位构成的数字排序后的结果(每行输出一个样本的结果)
示例1
输入
复制
4
abc123455
boyxx213456
cba312456
cdwxa654321
输出
复制
123455
213456
312456
654321
分析: 注意最后输出的排序是M个数字进行整体的排序。
n = int(input())
res = []
for i in range(n):
arr = input()
arr = arr[-6:]
res.append(int(arr))
res.sort()
for a in res:
print(a)