均衡操作
小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;
}

浙公网安备 33010602011771号