题目解析:
有一个序列A(a1,a2,a3......an),你可以进行以下操作:
选两个数ai, aj (1 <= i, j <= n),ai+1,aj-1。
问至少进行多少次操作,可以使A序列中任意两项的差不大于1。
方法一(写博客的时候想到的......):
算出平均值,与每一位求差。把差除以2,得到答案。
原理:
因为每次操作是把两个数,一个加一,一个减一。所以从数字上来讲,只是进行了一次搬运量为1的数字搬运。所以只要把每一位的值填到平均值,或是砍到平均值就可以了。
但是会有问题,因为不一定必须到平均值,所以会有多算的部分。不能拿全分,可以骗点。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 10;
int n, a[MAXN];
long long sum, ans;
int main()
{
cin >> n;
for (int i = 1; i <= n; ++ i)
{
cin >> a[i];
sum += a[i]; //求和
}
sum /= n; //算平均值
for (int i = 1; i <= n; ++ i)
ans = ans + abs(sum - a[i]); //求差
ans /= 2;
cout << ans << endl;
return 0;
}
方法二:
方法一虽然有问题,但不妨是一种思路。
我们只需要改一些地方,就可以满分。
求平均值,一个是 sum/n 直接求的,
另一个是前面的值加一。
因为会有一些数不用砍到最低的平均值。典型样例:
3
3 3 5
//只要砍到4, 但程序算的是3.能对只是巧合。
在用两个计数器。一个记录需要填到小平均值的数,一个记录需要砍到大平均值的数。
最后取较大的数。毕竟你不能为了少操作,不把别人变成平均值,使其不满足题意。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+5;
int N, a[maxn], c, d, d2, e, e2;
signed main(){
cin >> N;
for(int i = 1; i <= N; i ++)
{
cin >> a[i];
c += a[i];
}
d = c / N;
if(c % N == 0) d2=d;
else d2 = d + 1;
for(int i = 1; i <= N; i ++)
{
if(a[i] < d)
e += d - a[i];
if(a[i] >= d2)
e2 += a[i] - d2;
}
cout << max(e,e2) << endl;
return 0;
}
如果觉得看懂了,点个赞吧!