您的位置:首页 > 其它

XDOJ-1006-亮亮破解密码(数列中所有区间位操作值之和)

2017-04-12 18:28 791 查看
题目链接:XDOJ-1006-亮亮破解密码

考虑将每个数化为二进制,然后对二进制的每一位进行操作。

对于异或,处理出所有的后缀异或值,然后从后往前更新,维护其中值为1的数量和值为0的数量即可。

对于与,处理出所有连续1的数量,只有连续1与值才能为1

对于或,处理出所有连续0的数量。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
typedef long long ll;
double ans[3];
int n;
bool a[maxn][30];
int main()
{
while(~scanf("%d",&n))
{
int t;
for(int i=0;i<n;i++)
{
scanf("%d",&t);
for(int j=0;j<30;j++)
a[i][j]=(t>>j)&1;
}
int pre;
int c[2];
ans[0]=ans[1]=ans[2]=0;
for(int j=0;j<30;j++)
{
pre=0;
c[0]=c[1]=0;
ll res=0;
for(int i=n-1;i>=0;i--)
{
pre^=a[i][j];
++c[pre];
}
for(int i=n-1;i>=0;i--)
{
--c[a[i][j]];
res+=c[1]*2+a[i][j];
if(a[i][j]) swap(c[0],c[1]);
}
ans[0]+=res*1.0/n/n*(1<<j);
}

for(int j=0;j<30;j++)
{
ll cnt=0,res=0;
for(int i=0;i<=n;i++)
{
if(a[i][j]&&i!=n) cnt++;
else if(cnt)
{
res+=cnt*cnt;
cnt=0;
}
}
ans[1]+=res*1.0/n/n*(1<<j);
}

for(int j=0;j<30;j++)
{
ll cnt=0,res=1LL*n*n;
for(int i=0;i<=n;i++)
{
if(!a[i][j]&&i!=n) cnt++;
else if(cnt)
{
res-=cnt*cnt;
cnt=0;
}
}
ans[2]+=res*1.0/n/n*(1<<j);
}

printf("%.3f %.3f %.3f\n",ans[0],ans[1],ans[2]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: