『题解』CodeForces CF1543B Customising the Track

题目传送门

题目大意

\(T\) 组数据,每组数据给定一个长度为 \(n\) 的序列 \(a\),对其进行下列操作任意次:

  • 选择两个整数 \(i,j\) 满足 \(1 \leq i,j \leq n\)\(a_i>0\),使 \(a_i\) 减一,\(a_j\) 加一。

求操作后 \(\sum\limits^{n}_{i=1}\sum\limits^{n}_{j=i+1}|a_i-a_j|\) 的最小值。

思路

操作可以进行任意次,这说明我们可以使序列尽量平均。这样最终序列中只会有 \(1\) 种或 \(2\) 种数值。

关键在于输出,我们使用作差法即可。

对于作差,我们也可以进行推导优化。假设均分过后的数列有 \(2\) 种数值,那么较大数值的个数为 \(\sum\limits^{n}_{i=1} a_i \bmod n\),因为只存在 \(2\) 种数值,所以较大数值与较小数值作差的绝对值一定为 \(1\),那么我们的答案就是较大数值的个数乘较小数值的个数即 \([n\ ·\ (\sum\limits^{n}_{i=1} a_i) \bmod n]-[(\sum\limits^{n}_{i=1} a_i) \bmod n)]^2\)。——MikeC巨佬的题解

代码

#include <iostream>
using namespace std;
typedef long long ll;
ll t,n,sum;

inline ll read(){ // 整个快读省一个数组,O(1)空间复杂度
    ll X=0; bool flag=1; char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-') flag=0; ch=getchar();}
    while(ch>='0' && ch<='9') X=(X<<1)+(X<<3)+ch-'0',ch=getchar();
    if(flag) return X;
    return ~(X-1);
}

int main(){
    t=read();
    while(t--){
        n=read();
        for(ll i=1; i<=n; i++){
            sum+=read(); // 一脸坏笑😏
        }
        // 较大数的个数乘以较小数的个数就是答案qwq
        cout << (n-(sum%n))*(sum%n) << endl;
        sum=0; // 这个不能忘
    }
    return 0;
}
posted @ 2022-01-21 20:54  仙山有茗  阅读(24)  评论(0编辑  收藏  举报