题目描述:https://vjudge.net/problem/HDU-5933#author=0
#include<iostream>
#include<cstdio>
using namespace std;
long long a[110000];
int main(){
long long T;
cin >> T;
for(int i = 1;i <= T;i++)
{ long long sum = 0;
long long ans = 0;
long long n,k;
scanf("%lld%lld",&n,&k);
for(int j = 1;j <= n;j++)
{
scanf("%lld",&a[j]);
sum+=a[j];
}
//cout<<sum<<" "<<ans;
printf("Case #%d: ",i);
if (sum%k)
{
cout<<"-1"<<endl;
continue;
}
else
{ sum = sum/k;
for(int j = 1;j <=n;j++)
if(a[j]==sum || a[j]==0)
continue;
else
if (a[j] > sum)
{ans++;
a[j] = a[j] - sum;
j--; //亮点.
}
else if(a[j] < sum)
{
ans++;
a[j+1] +=a[j];
}
cout<<ans<<endl;
}
}
return 0;
}
前期出现过几次错误:
1.眼高手低,想了一种特例,.没有真的拿笔算,就排除了模拟的可能性.(以后一定要动笔!
2.没有想明白就瞎模拟.导致大量更改
大体解法:
1.首先肯定要判断总工位数是不是k的整数倍,如果不是直接输出-1
2.下面就是模拟,如果当前的数大于平均数,那就要把他拆开,不过注意直接再原数上剪掉平均数然后重新循环到这个点就行了,不要把原数剪掉平均数之后加到后面,画蛇添足.如果不足的话就直接把他加到的一个上,不要从后面借.
现在想想思路好清晰为当时会错…
第二种做法:
#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
int a[100004];
long long s[109003];
int main(){
int i;
int iCase;
scanf("%d",&iCase);
for(int k= 1;k <= iCase ;k++)
{
long long sum = 0;
scanf("%d%d",&n,&m);
for(i = 1;i <= n;i++)
{
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
sum+=a[i];
}
printf("Case #%d: ",k);
if (sum%m)
{
cout<<-1<<endl;
continue;
}
int aver = sum/m;
long long ans = 0;
for(i = 1;i< n;i++)
if (s[i]%aver == 0 )//边界重合,不需要操作
ans -= 2;
ans += n-1+m-1;
printf("%lld\n",ans);
}
return 0;
}
思路:通过前缀和判断
如果当前位置的前缀和是k的整数倍,那说明在这个点是不需要处理的.