N.Particle Arts(数学、位运算、“蔚来杯“2022牛客暑期多校训练营4)

题目

N.Particle Arts

在这里插入图片描

在这里插入图片描述

题目大意

给定一个数组,数组的任意两个元素按位与(&)和按位或(|),并将数组的那两个元素替换成按位与(&)和按位或(|)的运算结果,一直这样操作下去,直至数组的每个元素都不变,求出其方差,并按照题目要求的格式输出。

分析

通过观察可以发现一下几个特性
1、任意两个元素进行&和|操作时,元素每一位的1和0的个数是不变的
比如10和11   101&110=100   101|110=111
一开始是101和110,运算后变成了100和111
每一位的0的数量和1的数量还是相等的,最高位都是两个1,中间位都是1个0和1个1,最低位都是1个0和1个1。
2、知道了每一位的01个数相等,那么可以推出转变完的序列和转变前的序列和相等
3、与运算就相当于把0聚集到一个数身上,或运算相当于把1聚集到一个数身上

那么可以想到先计算出每一位的1的个数,1尽量分配到一起,如果那一位没有1分配,那么用0来,以此类推。

方差的公式通过数学可以转化为
n ( ∑ i = 1 n x 2 ) − s u m 2 n 2 \frac{n(\sum_{i=1}^nx^2)-sum^2}{n^2} n2n(i=1nx2)sum2

代码

#include<bits/stdc++.h>
using namespace std;
#define double long double 
typedef long long ll;
const ll mod=1e9+7;
const ll inf=0x3f3f3f3f;
const double eps=1e-10;
ll a[100009];
ll num[20];
void judge(ll x)
{
    ll flag=0;
    while(x)
    {
        if(x&1) num[flag]++;
        x/=2;
        flag++;
    }
}
ll get()
{
    ll ans=0;
    for(ll i=0;i<=17;i++)
    {
        if(num[i])
        {
            ans+=(1<<i);
            num[i]--;
        }
    }
    return ans;
}
void solve()
{
	ll n,i,j,sum=0;
	cin>>n;
	for(i=1;i<=n;i++) cin>>a[i],sum+=a[i];
	for(i=1;i<=n;i++)
    {
        judge(a[i]);
    }
    for(i=1;i<=n;i++)
    {
        a[i]=get();
    }
	ll tmp=0;
	for(i=1;i<=n;i++) tmp=tmp+a[i]*a[i];
	tmp=n*tmp-sum*sum;
	if(tmp==0) cout<<"0/1"<<endl;
	else
	{
		ll g=__gcd(tmp,n*n);
		cout<<tmp/g<<"/"<<n*n/g<<endl;
	}
	
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值