题目:
有 N 堆石子,每堆的石子数量分别为 a1,a2,…,aN。
你可以对石子堆进行合并操作,将两个相邻的石子堆合并为一个石子堆,例如,如果 a=[1,2,3,4,5],合并第 2,3堆石子,则石子堆集合变为a=[1,5,4,5]。
我们希望通过尽可能少的操作,使得石子堆集合中的每堆石子的数量都相同。
请你输出所需的最少操作次数。
本题一定有解,因为可以将所有石子堆合并为一堆。
输入格式
第一行包含整数T,表示共有T 组测试数据。
每组数据第一行包含整数N。
第二行包含N个整数 a1,a2,…,aN。
输出格式
每组数据输出一行结果。
数据范围
1≤T≤10 ,
1≤N≤10^5
0≤ai≤10^6,
每组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
样例解释
第一组数据,只需要用 3 个操作来完成:
1 2 3 1 1 1
-> 3 3 1 1 1
-> 3 3 2 1
-> 3 3 3
第二组数据,只需要用 2 个操作来完成:
2 2 3
-> 2 5
-> 7
第三组数据,我们什么都不需要做。
思路:假设总共有sum个石头,可以被分为a个组,每组的个数为cnt个,那么sum/cnt=a,所以每组所含有的个数(cnt)一定是sum的约数。因为一开始有n堆,没进行一次合并的操作,堆数-1,那么进行操作的次数为n-a。而a=sum/cnt;所以cnt越小越好。
对sum的每一个约数(从小到大)进行判断是否满足。
判断方法:因为只能相邻的两堆合并,那么对于一个数组而言,一定是相邻的数作合。如果有一段的和小于cnt,而加上这一段后面的一个数又大于cnt,那么表示这种情况不满足要求。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],n;
//判断每组个数为s时候是否满足
bool check(int s)
{
int temp=0;
for(int i=0;i<n;i++)
{
temp+=a[i];
if(temp==s)temp=0;
else if(temp>s)return false;
}
return true;
}
int main()
{
int t=0;
cin>>t;
while(t--)
{
int sum=0;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
sum+=a[i];
}
//i表示最后所剩的堆数,每一组的个数为sum/i;
for(int i=n;i>0;i--)
{
if(sum%i==0&&check(sum/i))
{
cout<<n-i<<endl;
break;
}
}
}
return 0;
}