您的位置:首页 > 编程语言 > Python开发

【python学习笔记】几道笔试题(2)

2018-03-27 11:03 134 查看
最近要申暑期实习,在牛客、赛码上做了一些真题,在这里将其中一部分错题做个整理。
第一题:
小东和其他小朋友正在玩一个关于选举的游戏。选举是通过投票的方式进行的,得票最多的人将获胜。

小东是编号为1的候选者,此外还有其他的候选者参加选举。根据初步的调查情况,所有准备投票的小朋友都有一定的投票倾向性,小东如果要获得胜利,必须争取部分准备为其他候选人投票的小朋友。由于小东的资源较为有限,她希望用最小的代价赢得胜利,请你帮忙计算她最少需要争取的选票数。
输入:
输入有若干组,每组包含两行,第一行为一个正整数n(2<=n<=100),表示候选者的数量,第二行为每个候选人预期得到的选票数,以空格分开,每人的预期得票数在1到1000之间(包含1和1000)。

经过小东的争取后,可能出现候选人得票数为0或超过1000的情况。
输出:
对每组测试数据,单独输出一行,内容为小东最少需要争取的选票数。

样例输入:5
5 1 11 2 8
4
1 8 8 8
2
7 6样例输出:4
6
0尝试:while True:
n = int(raw_input())
s = map(int, raw_input().split())
s0 = s[0]
s1 = s[0]
s[0] = 0
while max(s)>=s1:
maxIndex = s.index(max(s))
add = (max(s) - s1)//2 + 1
s1 += add
s[maxIndex] -= add
print(str(s1-s0))思路:将小东初始选票存为s0,当前选票存为s1,并把s[0]置为0防止max函数取到。接下来判断s中是否有超过s1的值,如果有则将该值减少与s1的差的一半加一,s1增加与最大值的差的一半加一。
算法未能跑通所有测试用例。
分析:当s中最大值与s1的差是奇数时,如7,差地板除2再加1等于4,s1超过当前最大值;当s中最大值与s1的差是偶数时,如8,差地板除2再加1等于5,s1超过当前最大值。但考虑到最大值是动态变化的,一次调整得过大会造成最大值减小过快,远远低于第二大的值,因此应每次仅加减1,即可保证不出错。

修改:while True:
n = int(raw_input())
s = map(int, raw_input().split())
s0 = s[0]
s1 = s[0]
s[0] = 0
while max(s)>=s1:
maxIndex = s.index(max(s))
s1 += 1
s[maxIndex] -= 1
print(str(s1-s0))第二题:
有5个人ABCDE排队,排好后他们决定重新排队,每个人都不在原来的位置上,那么总共有多少种排法?

解:n个人每个人都不站在原来的位置的方法数有f(n)=n!(1/2!-1/3!+1/4!+..+(-1)^n*1/n!),代入n=5,解为44.

第三题:
小明买了一些彩色的气球用绳子串在一条线上,想要装饰房间,每个气球都染上了一种颜色,每个气球的形状都是各不相同的。我们用1到9一共9个数字表示不同的颜色,如12345则表示一串5个颜色各不相同的气球串。但小明希望得到不出现重复颜色的气球串,那么现在小明需要将这个气球串剪成多个较短的气球串,小明一共有多少种剪法?如原气球串12345的一种是剪法是剪成12和345两个气球串。

注意每种剪法需满足最后的子串中气球颜色各不相同(如果满足该条件,允许不剪,即保留原串)。两种剪法不同当且仅当存在一个位置,在一种剪法里剪开了,而在另一种中没剪开。详见样例分析。
输入:
第一行输入一个正整数n(1≤n≤100000),表示气球的数量。
第二行输入n个整数a1,a2,a3...an,ai表示该气球串上第i个气球的颜色。对于任意i,有1≤ai≤9。

输出:
输出一行,第一行输出一个整数,表示满足要求的剪法,输出最终结果除以1000000007后的余数。

尝试:def cal(n):
res = 1
for i in range(1, n):
resTemp = 1
for j in range(i):
resTemp = resTemp*(n-j-1)/(j+1)
res = res+int(resTemp)
return res

if __name__ == '__main__':
n = int(raw_input())
nArr = list(map(int, raw_input().split()))
res = 1
resTemp = []
lastEle = nArr[0]
lastLen = 1
for i in nArr[1:]:
if i != lastEle:
lastEle = i
lastLen = lastLen+1
else:
res = res*cal(lastLen)
lastLen = 1
res = res*cal(lastLen)
print(str(res))思路:因为相同元素不能存在于同一子串中,因此所有相邻的相同元素间都需要切开。切开后计算前一子串可分割的更小子串数,所有结果相乘,即为总的可能分割数。具体方法是遍历气球串数组,如果两相同元素相邻,就在此处切开,计算前一部分可分割的子串数(cal函数)并与已有结果相乘,继续遍历,直到尾部。遍历完成后计算尾部子串可继续分割子串数并与已有结果相乘。
结果未能跑通所有测试用例。
分析:对于12332这种类型的情况,该方法能得出正确结果;如果用例变为32332,该方法只会在33中间切一刀,之后分别计算两子串可分割数并相乘。而实际上前一子串已有3这个元素,不能将3再放入其中。
修改:if __name__ == '__main__':
n = int(raw_input())
nArr = list(map(int, raw_input().split()))
dp = [1]
for i in range(1, n+1):
col = [0 for j in range(10)]
d = 0
for j in range(1, i+1):
col[nArr[i-j]] = col[nArr[i-j]]+1
if col[nArr[i-j]]>1:
break
d = d+dp[i-j]
dp.append(d)
print(dp[-1]%1000000007)思路:构造数组dp,dp[i]表示遍历到位置i时满足条件的划分数。计算i+1时向前遍历dp,直到遍历到某一位置k使得包含k后不满足条件,此时dp[i+1]的值为数组dp[k]到dp[i]的连加。外层循环遍历n,最坏情况下内层循环由1至n,根据欧拉公式,时间复杂度为o(nlogn)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: