AcWing 4366. 上课睡觉
原题
有 N堆石子,每堆的石子数量分别为 a1,a2,…,aN1,2,…,。
你可以对石子堆进行合并操作,将两个相邻的石子堆合并为一个石子堆,例如,如果 a=[1,2,3,4,5]=[1,2,3,4,5],合并第 2,32,3 堆石子,则石子堆集合变为 a=[1,5,4,5]=[1,5,4,5]。
我们希望通过尽可能少的操作,使得石子堆集合中的每堆石子的数量都相同。
请你输出所需的最少操作次数。
本题一定有解,因为可以将所有石子堆合并为一堆。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含整数 N。
第二行包含 N个整数 a1,a2,…,aN1,2,…,。
输出格式
每组数据输出一行结果。
数据范围
1≤T≤10^10,
1≤N≤10^5,
0≤ai≤10^6,
∑i=1~n ai≤10^6,
每个输入所有 N 之和不超过 10^5。
输入样例:
3
6
1 2 3 1 1 1
3
2 2 3
5
0 0 0 0 0
输出样例:
3
2
0
样例解释
第一组数据,只需要用 33 个操作来完成:
1 2 3 1 1 1
-> 3 3 1 1 1
-> 3 3 2 1
-> 3 3 3
第二组数据,只需要用 22 个操作来完成:
2 2 3
-> 2 5
-> 7
第三组数据,我们什么都不需要做。
正确题解
# AcWing 4366. 上课睡觉
T=int(input())
lisyue=[]
for i in range(0,T):
lenth=int(input())
lis=input().split(' ')
lisn=[int(num) for num in lis]
lissum=sum(lisn)
liscount=[]
for i in range(1,lissum+1):
if lissum%i==0:
liscount.append(i)
yueshu=0
for count in liscount:
psum=0
for item in lisn:
psum+=item
if psum<count:
flag=0
elif psum==count:
flag=1
psum=0
else:
flag=0
break
if flag==1:
yueshu=count
break
if yueshu==0:
lisyue.append(0)
continue
lisyue.append(lenth-lissum/yueshu)
for i in lisyue:
print(int(i))
解题思路
- 1.最终得到的结果每堆的总和一定是那一行N个数字的约数count,所以只要将一个连续的序列(输入的N个数),划分成若干段,每段和=count即可,最后需要操作的次数=n-N个数的sum/count(因为要最小的操作次数,所以count越小越好)
- 2.特殊处理:如果那一段的和为0(则没有约数,sum=0,count=null),则直接需要合并次数=0,因为a_i大于=0,如果等于0则说明那一段的都是0
- 3.如何划分?可以从前往后遍历每一段,如果段和小于count则继续往后走,大于count则说明这个约数不能满足条件,换成下一个count
- 4.这个能直接遍历而不会超时的原因:一般时间要求控制在12秒,即操作次数控制在10^7108,而每一行的数字总数小于105,和为10^6以内的最多的约数个数为240个,所以不会超时