CCF CSP认证 历年题目自练Day14
题目一
小明今天生日,他有n块蛋糕要分给朋友们吃,这n块蛋糕(编号为1到n)的重量分别为a1, a2, …, an。小明想分给每个朋友至少重量为k的蛋糕。小明的朋友们已经排好队准备领蛋糕,对于每个朋友,小明总是先将自己手中编号最小的蛋糕分给他,当这个朋友所分得蛋糕的重量不到k时,再继续将剩下的蛋糕中编号最小的给他,直到小明的蛋糕分完或者这个朋友分到的蛋糕的总重量大于等于k。
请问当小明的蛋糕分完时,总共有多少个朋友分到了蛋糕。
输入格式
输入的第一行包含了两个整数n, k,意义如上所述。
第二行包含n个正整数,依次表示a1, a2, …, an。
输出格式
输出一个整数,表示有多少个朋友分到了蛋糕。
样例输入
6 9
2 6 5 6 3 5
样例输出
3
样例说明
第一个朋友分到了前3块蛋糕,第二个朋友分到了第4、5块蛋糕,第三个朋友分到了最后一块蛋糕。
评测用例规模与约定
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ k ≤ 10000,1 ≤ ai ≤ 1000。
题目分析(个人理解)
- 简单题直接看输入,n是有几块蛋糕,k是每个小朋友最少分到到重量。
- n,k=map(int,input().split())
- 第二行输入小明拥有的每块蛋糕的重量。我选择列表存储,核心算法是这样的,从,小明拥有的第一个蛋糕开始算起,满足大于等于k的,计数器加一(计数器用来统计能给几个小朋友发),不满足的遍历小明拥有的蛋糕的重量,一直到满足大于等于k,计数器加一,一直把小明的蛋糕遍历完,最后输出计数器,如果最后一块蛋糕即使不满足条件,也要发给小朋友。
- num_list=list(map(int,input().split()) num_list[]存储每块蛋糕的重量。
- result=0#计数能给几个小朋友发蛋糕。
- temp作为累加器,统计每一次遍历的蛋糕重量是否满足条件,满足则归零做下一次统计。
- 完整代码如下!!!
n,k=map(int,input().split())
num_list=list(map(int,input().split()))
result=0
temp=0
for i in range(n):
temp=temp+num_list[i]
if temp>=k:
result+=1
temp=0
if temp>0:
result+=1
print(result)
题目二
问题描述
体育老师小明要将自己班上的学生按顺序排队。他首先让学生按学号从小到大的顺序排成一排,学号小的排在前面,然后进行多次调整。一次调整小明可能让一位同学出队,向前或者向后移动一段距离后再插入队列。
例如,下面给出了一组移动的例子,例子中学生的人数为8人。
0)初始队列中学生的学号依次为1, 2, 3, 4, 5, 6, 7, 8;
1)第一次调整,命令为“3号同学向后移动2”,表示3号同学出队,向后移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 3, 6, 7, 8;
2)第二次调整,命令为“8号同学向前移动3”,表示8号同学出队,向前移动3名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 8, 3, 6, 7;
3)第三次调整,命令为“3号同学向前移动2”,表示3号同学出队,向前移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 3, 5, 8, 6, 7。
小明记录了所有调整的过程,请问,最终从前向后所有学生的学号依次是多少?
请特别注意,上述移动过程中所涉及的号码指的是学号,而不是在队伍中的位置。在向后移动时,移动的距离不超过对应同学后面的人数,如果向后移动的距离正好等于对应同学后面的人数则该同学会移动到队列的最后面。在向前移动时,移动的距离不超过对应同学前面的人数,如果向前移动的距离正好等于对应同学前面的人数则该同学会移动到队列的最前面。
输入格式
输入的第一行包含一个整数n,表示学生的数量,学生的学号由1到n编号。
第二行包含一个整数m,表示调整的次数。
接下来m行,每行两个整数p, q,如果q为正,表示学号为p的同学向后移动q,如果q为负,表示学号为p的同学向前移动-q。
输出格式
输出一行,包含n个整数,相邻两个整数之间由一个空格分隔,表示最终从前向后所有学生的学号。
样例
输入:
8
3
3 2
8 -3
3 -2
1
2
3
4
5
输出:
1 2 4 3 5 8 6 7
1
评测用例规模与约定
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 1000,所有移动均合法。
题目分析(个人理解)
- 还是先看输入,第一行输入n个整数,直接n=int(input())
- 给n个空间,还是选择列表存储先看看行不行,给一个列表l[],我用列表的值代表学生的编号,尤其注意编号从1开始,所以,for i in range(1,n+1)
- 接着再看输入的第二行,确定要改变的学生的个数,常规输入即可,m=int(input())
- 后面的就是输入哪个编号的学生要改变,怎样改变位置的输入,我用p表示要改变的学生的编号,q表示怎样改变。
- for i in range(m):
p,q=map(int,input().split()) - 到核心部分了!对于学生怎样移动有两种情况,第一种情况是选中的学生向后移动,那么必然有如下步骤,比如,我要将位序为i的编号向后移动n个单元,首先把要移动的学生编号拿出去,假如我要移动的学生编号在位序为 i 的位置,先把 i 号位置的编号存到另一个列表,然后将 i+1 到 i+n 位置的编号位序加1(即实现前移操作),最后将拿出来的学生编号插入i+n位置即可。
- 第二种情况是选中的学生向前移动,可以类比向后移动去思考,同理可得代码。
- 完整代码如下!!!
n=int(input())
l=[]
for i in range(1,n+1):
l+=[i]
m=int(input())
for i in range(m):
p,q=map(int,input().split())
if q>0:# 后移
for j in range(n):# 找到所要移动的元素位置,用k记录
if l[j]==p:
k=j
continue
st=l[k]#把改变的编号拎出来,单独存
for j in range(q):# 将k+1到k+q位置的元素前移一个位置
l[k+j]=l[k+j+1]
l[k+q]=st#把拎出来的插入
else:# 前移
for j in range(n):
if l[j]==p:
k=j
continue
st=l[k]#把改变的编号拎出来,单独存
for j in range(abs(q)):#abs为绝对值函数---k-j---k-j-1
l[k+j]=l[k+j-1]
l[k+q]=stst#把拎出来的插入
print(l[0],end='')
for i in range(1,n):
print('',l[i],end='')
- 你以为这就完了?当然不能,还有第二种方法!!!
- 可以把要改变的编号和改变多少个位置分别存储在两个列表中。
- 这里核心算法有一些改变,我还是先将要改变位置的编号找到,然后直接用pop()放法直接删除,然后再把删除的,(也就是要改变的编号)插入它该在的位置即可,这样比第一种方法简单很多。不用考虑是向前还是向后,全部在存储改变位置的列表中体现。
- 我选择index()函数和pop()函数会复杂的问题简单化。pop()函数返回删除的值。index() 函数用于从列表中找出某个值第一个匹配项的索引位置。
语法
index()方法语法:
list.index(x[, start[, end]])
参数
x-- 查找的对象。
start-- 可选,查找的起始位置。
end-- 可选,查找的结束位置。
返回值
该方法返回查找对象的索引位置,如果没有找到对象则抛出异常。
实例
List = [‘123’, ‘abc’, ‘teacher’, ‘school’]
print("abc索引位置: ", List.index(‘abc’))
print("123索引位置 : ", List.index( ‘123’, 0, 3 ))
1
2
3
4
返回结果如下:
abc索引位置: 1
123索引位置 : 0 - 直接上代码!!!
n=int(input())#总共有几个学生
m=int(input()) #调整次数
list_a=[] #调整学生
list_b=[] #调整的操作存储
#生成学号
stu=[int(i) for i in range(1,n+1)]#迭代写入
for i in range(m):
a,b=map(int,input().split())
list_b.append(b)
list_a.append(a)
#print(list_b,list_a,stu)
for i in range(m):
k=stu.index(list_a[i]) #获取被删除元素索引
obj=stu.pop(k) #s删除此位置的值
stu.insert(k+list_b[i],obj)#插入删除的值
#print(stu)
for i in range(len(stu)):
print(stu[i],end=' ')
总结
对于python熟悉每个函数和方法的用法至关重要!!!