均衡操作
小J面前有N桶水,每个桶装的水的体积不一样
现在小J希望让所有桶的水的体积变得一样
每次他会选择两个相邻的桶子,将一个桶的水倒入另一个桶,然后将空桶丢掉。
问他至少操作多少次,使得所有桶的水一样多。
Format
Input
第一行给出数字T,代表数据的组数
对于每组数据,先给出N
下面一行给出N个数字,代表每个桶的水的体积
N<=1e5
T<=10
所有数字之和<=1e6
Output
如题
Samples
输入数据 1
1
6
1 2 3 1 1 1
输出数据 1
3
Hint
第1次,小J将第1个与第2个桶合并,得到数列(3,3,1,1,1)
第2次,小J将第4个与第5个桶合并,得到数列(3,3,1,2)
第2次,小J将第3个与第4个桶合并,得到数列(3,3,3)
Sol:
每个水桶开始的体积知道了,于是总体积sum也就知道了。
发现每次合并就减少一个桶,于是如果知道最终还有多少个桶,就知道了合并了几次
于是我们逆序枚举一下,最终还有多少个桶,设之为i
于是每个桶最终的体积为sum/i,自然sum%i必须为0
接下来,我们就来检查一下,合并的过程中是否有出错
由于在合并时,是不断将小数字合并成一个大数字,于是如果发现合并后的体积,或者某个水桶目前的体积是大于sum/i的,则合并是出错的。
例如
4个桶
1 2 3 6
于是sum=1+2+3+6=12
假设i=3,于是sum/i=12/3=4
于是我们从左扫到右
就会发现1+2+3=6>4
于是合并失败
再让i=2,sum/i=12/2=6
发现合并的过程是不会出错的。
于是合并的次数就等于 N-i=4-2=2
总结:
这个题还是比较简单的,有多种枚举方式,例如枚举最终每个桶的水的体积是多少。
当然这个体积也必须是总体积sum的约数才行。
方法1:枚举最终留下多少个桶
#include<bits/stdc++.h> using namespace std; int a[1000006]; int main() { int T; cin >> T; while (T--) { int n; cin >> n; int sum = 0; for (int i = 0; i < n; i++) { cin >> a[i]; sum += a[i]; } int ans; for (int i = n; i >= 1; i--) //最后剩下多少堆 { if (sum % i != 0) continue; int cur = 0; bool flag = 1; for (int j = 0; j < n; j++) { cur += a[j]; if (cur > sum / i) { flag = 0; break; } else if (cur == sum / i) { cur = 0; } } if (flag) { ans = n - i; break; } } cout << ans << endl; } return 0; }
方法2:枚举体积
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; int t,n,s,cnt,a[maxn],p[1005],res,ans; bool flag; int main() { scanf("%d",&t); while(t--) { flag=ans=cnt=s=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); flag|=(a[i]!=a[1]); s+=a[i]; } if(!flag) { printf("0\n"); continue; } for(int i=1;i<=s;i++) { if(s%i) continue; p[++cnt]=i; } for(int i=1;i<=cnt;i++) //枚举每个桶里有多少水,从小到大枚举,找到第一个解就退出 { res=ans=0; bool ok=true; for(int j=1;j<=n;j++) { res+=a[j]; ans++; if(res==p[i]) { res=0; ans--; } if(res>p[i]) { ok=false; break; } } if (ok==true) { printf("%d\n",ans); break; } } } return 0; }