题目大意:不告诉你QAQ
直接搬题解辣
对于位运算的题目,我们都可以把数拆成二进制,一位一位分开来考虑。那么我们只需要考虑0,1串的情况。我们枚举每一位作为连续段末端点R,
对于or:如果这一位为0,那么我们需要找到前面最近的一个1,L在这之前的(L,R)的结果都是1,其它都是0,统计入答案;
如果这一位为1,那么所有的(L,R)结果都是1,直接计入答案。
对于and:如果这一位为0,结果都是0,答案直接不加。
如果这一位为1,我们找之前最近的0,L在这之后的(L,R)的结果为1,其它为0,统计入答案。
对于xor,我们需要知道之前xor完答案为0的(L,R-1)有几个,答案为1的(L,R-1)有几个,知道之后我们也可以统计答案。
而找最近的1,最近的0,以及之前xor完答案为0,1的有几个,这些我们可以在扫描过程中得到答案,所以做一遍是O(N),
我们做31遍即可得出每一位上的答案,就算出最终答案了。
注意:本题设定L>R也是有意义的,写的时候要注意这一点。
竟然不同调就A了(赛后QAQ)
爽!!!
#include<cstdio>
#include<cstring>
const int N=1e5+7;
int a[N];
int main()
{
freopen("nine.in","r",stdin);
freopen("nine.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
long long sum1=0,sum2=0,sum3=0;
int qu1=0,qu0=0;
int ans1=0,ans0=0;
for(int i=0;i<=30;i++)
{
int kkk=(1<<i);
qu1=0,qu0=0;
ans1=0,ans0=0;
for(int r=1;r<=n;r++)
{
if(a[r]&kkk)
{
sum3+=(long long)kkk*(2*r-1);
sum2+=(long long)kkk*(r*2-qu0*2-1);
qu1=r;
sum1+=(long long )kkk*ans0*2;
sum1+=kkk;
int tem0=ans0,tem1=ans1;
ans0=tem1;
ans1=tem0+1;
}
else
{
sum3+=(long long )kkk*qu1*2;
qu0=r;
sum1+=(long long )kkk*ans1*2;
int tem0=ans0,tem1=ans1;
ans0=tem0+1;
ans1=tem1;
}
}
}
long long ttt=(long long )n*n;
printf("%.3f %.3f %.3f\n",sum1*1.0/ttt,sum2*1.0/ttt,sum3*1.0/ttt);
fclose(stdin);
fclose(stdout);
return 0;
}