看到黄大神和某不知名的INnoVation神犇已经开始切XDOJ了,好可啪。。。自己也赶忙做几道题水水以假装自己不是弱鸡。。。然而咸鱼的现实并不能改变,第一道题就路途艰难QAQ
第一眼看这题就往线段树想。。然后并没有什么作用。。然后突然感觉该不会是树套树?!有点慌了。。然后偷偷瞄了一眼黄大神的代码长度排除了这种可能。。。
然后稍微模拟了一下发现把数列拆成一列一列分析会很方便(果然模拟是算法的来源啊。。)
拆分后,对某位数i,如果i是0那对求与的贡献就是0了,从i起找到第一个1对求或就有贡献了;如果i是1从i起找到第一个0就没贡献了,而对求与一直有贡献。。当然第一个1和0可以预处理,然后求区间长度。。。
对异或可以利用其自反性处理一个前缀异或d[n]。。然后统计i之后和d[i-1]异或为1的个数(同样可以预处理)就可以。。。
然后麻烦的就是这题还爆longlong。。还要输出小数什么的。。由于很久都没写过高精度之类的所以时间主要用在了在处理精度问题这里qaq
对于高精度这一个麻烦的问题。。可不可以扔给队友(逃
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define inf 100000
#define ll long long
#define succ(x) (1<<x)
#define lowbit(x) (x&&(-x))
#define NM 100005
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int n,m,a[NM],b[NM],c[NM],d[NM],f0[NM],f1[NM],_x,_y;
ll t,ans1,ans2,ans,s1[50],s2[50],s[50],tmp,_ans,_ans1,_ans2;
int main(){
freopen("data.in","r",stdin);
m=30;
while(~scanf("%d",&n)){
tmp=0;mem(s);mem(s1);mem(s2);
inc(i,1,n)a[i]=read();
inc(i,1,n)tmp+=a[i];
t=1;ans=ans1=ans2=_ans=_ans1=_ans2=0;
inc(p,1,m){
mem(b);mem(c);mem(d);mem(f0);mem(f1);
_x=_y=n+1;
dec(i,n,1){
b[i]=_x;c[i]=_y;
if(a[i]%2)_x=i;else _y=i;
}
inc(i,1,n)d[i]=d[i-1]^(a[i]%2);
dec(i,n,1){
f1[i]=f1[i+1];f0[i]=f0[i+1];
if(d[i])f1[i]++;else f0[i]++;
}
inc(i,1,n){
if(a[i]%2)s1[p]+=c[i]-i-1,s2[p]+=n-i;
else s2[p]+=n+1-b[i];
if(d[i-1])s[p]+=f0[i+1];else s[p]+=f1[i+1];
}
// inc(i,1,n)printf("%d ",d[i]);printf("\n");
inc(i,1,n)a[i]>>=1;
t*=2;
}
t=2;ans1=ans2=ans=tmp;
inc(i,1,m){
ans1+=t*s1[i];_ans1+=ans1/inf;ans1%=inf;
ans2+=t*s2[i];_ans2+=ans2/inf;ans2%=inf;
ans+=t*s[i];_ans+=ans/inf;ans%=inf;
t<<=1;
}
t=(ll)n*n;
ans+=_ans%t*inf;_ans=_ans/t*inf+ans/t;ans%=t;ans+=_ans%10*t;_ans/=10;
ans1+=_ans1%t*inf;_ans1=_ans1/t*inf+ans1/t;ans1%=t;ans1+=_ans1%10*t;_ans1/=10;
ans2+=_ans2%t*inf;_ans2=_ans2/t*inf+ans2/t;ans2%=t;ans2+=_ans2%10*t;_ans2/=10;
if(_ans)printf("%lld",_ans);printf("%.3lf ",(double)ans/t);
if(_ans1)printf("%lld",_ans1);printf("%.3lf ",(double)ans1/t);
if(_ans2)printf("%lld",_ans2);printf("%.3lf\n",(double)ans2/t);
// printf("%lld %lld %lld\n",ans,ans1,ans2);
}
return 0;
}
1006: 亮亮破解密码
时间限制: 2 Sec 内存限制: 128 MB
提交: 94 解决: 22
[提交][状态][讨论版]
题目描述
小W为了防止亮亮拿他的电脑打Loly of Lord(LoL),给电脑设置了密码。而亮亮是一位非常高富帅的苹果用户,不屑于在自己的Macbook上装Windows,又不敢用实验室流量装Wine,就没法拿自己的电脑打LOL。因此,他用尽各种办法试图破解小W的密码。一天,小W打Coding Flood(CF)比赛时AK了,心情很好,就给了亮亮一个很长的数列A={a1,a2,...,aN},并告诉他:自己的Windows密码由三部分组成,每部分都能由这个数列得到。密码的计算方式如下:
在1~N这N个数中,等概率地选取两个数l、r。如果l>r,则交换l、r。把信号中的第l个数到第r个数取出来,构成一个数列P={al,al+1,...,ar}。
第一部分的密码是数列P中所有数按位异或(^)操作后得到的数的数学期望。
第二部分的密码是数列P中所有数按位与(&)操作后得到的数的数学期望。
第三部分的密码是数列P中所有数按位或(|)操作后得到的数的数学期望。
请你帮助亮亮求出这三部分密码。小W透露,他的密码在小数点后保留了3位。
输入
输入包含多组数据,请处理到EOF。
每组数据,第一行,一个整数N。第二行,N个整数a1,a2,...,aN。
对于100%的数据,1<=N<=100000,0<=ai<230。
输出
对于每组测试数据,输出一行,包含三个实数,用空格分割,表示三部分的密码。
样例输入
2
4 5
3
1 0 1
样例输出
2.750 4.250 4.750
0.667 0.222 0.889
提示
样例1共包含4种可能的(l,r):
l,r xor and or
1,1 4 4 4
1,2 1 4 5
2,1 1 4 5
2,2 5 5 5
以上每一对(l,r)出现的概率相同,故对它们取平均数就是数学期望。
来源
XDUACM 2014暑期集训第7场
[提交][状态][讨论版]