首先这道题的中文意思
下面是题目给的公式(看不懂也没关系)
输入描述
第一行包含一个整数 n (2≤n≤10^15) 表示粒子的个数。 第二行包括n个整数 a1,a2...an(0≤ai<2^15) 表示第i个粒子所携带的能量。
输出描述
为一个不可化简的分数形式a/b(b>0)要确保gcd(a,b)=1或者当a=0时,b=1。
解题思路
这道题有 与 和 或 的位运算所以我们将它先化成二级制。
如3 5两个数字
011和101进行上述2则运算,结果为001和111,然后001和111进行运算结果依旧为001和111。我们可以发现他们的和没有变化都为8,换句话说就是“1”的位置发生了变化,而发生了一次变化后也不会再发生变化即两个值恒稳定。
接下来看样例:
输入:5
1 2 3 4 5
输出:54/5
则二进制为:
001
010
011
100
101
为了让他们不再发生碰撞即值稳定,我们将“1”的位置移到一起:
000
000
001
111
111
这个时候值就稳定了,接下来就是算方差了。
为了节省时间复杂度以及空间复杂度(代码少,懒得写)就用下述这个公式
方差=每个数的平方的平均数-平均数的平方
int sum=0,ans=0,cnt=0;
for(int i=1;i<=n;i++)
{
sum+=a[i];
cnt+=a[i]*a[i];//每个数的平方
}
//ans=cnt/n-sum/n*sum/n这边为了防止小数出现我们乘上n*n
ans=cnt*n-sum*sum;
//最后在求出gcd即可
最后给出代码
#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;//将他们二进制的“1”累加起来
x/=2;
k++;
}
}
ll sum=0,summ=0,ans=0;
for(int i=1;i<=n;i++){ //将二进制换成10进制
for(int j=15;j>=0;j--){//这边范围是2^15次所以循环15
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*sum;
ll g=__gcd(ans,n*n);
cout<<ans/g<<"/"<<n*n/g;
}