"蔚来杯"2022牛客暑期多校训练营4 N Particle Arts
题面
样例
输入:
5
1 2 3 4 5
输出:
54/5
题目链接 :https://ac.nowcoder.com/acm/contest/33189/N
瞎分析
经过手推可以发现,经过亿次碰撞,任意两个数字碰撞都会有[a|b=a,a&b=b] (a≥b)
然后可以发现就是把每一位的1尽量填到一个数字里。
例如,样例{1,2,3,4,5}化成2进制
∣
001
010
011
100
101
∣
\begin{vmatrix}001\\010\\011\\100\\101\end{vmatrix}
∣
∣001010011100101∣
∣
然后经过碰撞可以变成
∣
000
000
001
111
111
∣
\begin{vmatrix}000\\000\\001\\111\\111\end{vmatrix}
∣
∣000000001111111∣
∣
可以发现就是把每一位的1做一个“下沉”操作。
此时,任何两个数字碰撞也不会产生新的数字。
然后计算数组的方差就是答案
方差公式:
s
2
=
∑
i
=
1
n
x
i
2
/
n
−
(
∑
i
=
1
n
x
i
/
n
)
2
s^2=\sum_{i=1}^nx_i^2/n-(\sum_{i=1}^nx_i/n)^2
s2=∑i=1nxi2/n−(∑i=1nxi/n)2
说人话就是平方的的平均数减去平均数的平方
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n;
ll a[100100];
ll b[20];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
int k=0;
while(x){
b[k]+=x%2;
x/=2;
k++;
}
}
ll sum=0,summ=0,ans=0;
for(int i=1;i<=n;i++){
for(int j=15;j>=0;j--){
if(b[j]){
a[i]=a[i]*2+1;
b[j]--;
}
else a[i]*=2;
}
sum+=a[i];
summ+=a[i]*a[i];
}
/*
神奇的化简
下面附上原来的版本
ans=summ/n-(sum/n)*(sum/n);
ll g=__gcd(ans,1);
cout<<ans/g<<"/"<<1/g;
因为输出要求不得不改
*/
ans=summ*n-sum*sum;
ll g=__gcd(ans,n*n);
cout<<ans/g<<"/"<<n*n/g;
}