2022牛客多校4 N Particle Arts
作者:互联网
https://ac.nowcoder.com/acm/contest/33189/N
题意:
给\(n\)个数,每次任选两个数\(a,b\),变成两个新数\(a|b\)和\(a\&b\),在进行若干次操作后,数列会处于稳定,求方差
解法:
观察操作我们会发现,在操作前后,每一位上的1的数量不会发生变化,如果有两个1,与和或产生的都是1,如果有一个1,只有与是1,如果没有1,结果也没有1,所以两个数的和也不会发生变化。
继续观察操作我们会发现,1会尽可能地向一个方向靠拢,也就是说,尽可能让其中一个数每一位都是1,另一个数拿剩下的1,那么不论进行多少次操作,这种特性依然存在
所以最终就是先求出每一位1出现的次数,然后构造新的数列,新的数列是非严格递减的,如果某一位还有剩余的1就尽可能往前放。
这道题有个易错点就是用long long需要注意优化分数运算,很容易爆掉,我就改了好久,最后换成int128了
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc getchar
#define maxn 100005
#define maxm 20
using namespace std;
inline ll read(){
ll a=0;int f=0;char p=gc();
while(!isdigit(p)){f|=p=='-';p=gc();}
while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
return f?-a:a;
}int n;
ll a[maxn],b[maxm];
__int128 sum;
__int128 gcd(__int128 a,__int128 b){
return a%b==0?b:gcd(b,a%b);
}
struct ahaha{
__int128 a,b;
inline void merge(){
__int128 c=gcd(a,b);
a/=c,b/=c;
}
inline ahaha friend operator+(const ahaha x,const ahaha y){
ahaha c;
__int128 zz=gcd(x.b,y.b);
c.b=x.b/zz*y.b;
c.a=y.b/zz*x.a+x.b/zz*y.a;
c.merge();
return c;
}
}u,ans;
inline void chuli(int p){
for(int i=15;~i;--i)
if((1<<i)&p){
++b[i];
sum+=1<<i;
}
}
void print(__int128 x){
if(x>9)print(x/10);
putchar(x%10+'0');
}
int main(){
n=read();ans.b=1;
for(int i=1;i<=n;++i){
a[i]=read();
chuli(a[i]);
}
u.a=sum,u.b=n;
u.merge();
for(int i=1;i<=n;++i){
a[i]=0;
for(int j=15;~j;--j)
if(b[j]){
a[i]+=1<<j;
--b[j];
}
ahaha zz;
zz.a=a[i]*u.b-u.a;
zz.b=u.b;
zz.merge();
zz.a*=zz.a;
zz.b*=zz.b;
zz.merge();
ans=ans+zz;
ans.merge();
}
ll p=gcd(ans.a,n);
ans.a/=p;n/=p;
ans.b*=n;
ans.merge();
print(ans.a);
putchar('/');
print(ans.b);
return 0;
}
标签:Arts,Particle,int,ll,long,牛客,gc,include,define 来源: https://www.cnblogs.com/hanruyun/p/16541682.html