『题解』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;
}