jzoj3442&3816 期望异或&&大新闻

来源:互联网 发布:如何还房贷最划算知乎 编辑:程序博客网 时间:2024/04/28 03:43

双倍经验get
第一个用cpp打的 666

题目描述

给定一个区间[0,n), 现在在这个区间内等概率的选取一个数x,然后有p的几率我们可以直接选择这个区间内异或上x和最大的数y,另外1-p的几率也是在这个区间中等概率的选择一个数y,求x⊕y的期望值.
形态形成场好像不是什么好东西 bl
n<=1018

我们将他分为成功与不成功两个部分计算
由题意知

Ans=(1p)1n2xy+p1nxf(x)

f(x)=在此区间内与x异或 和最大的数

因为是异或,显然每一位是可以独立算贡献的 (论位运算的拆位重要性)
那么问题就转化为了有a个0,b个1 共n个,等概率取x,y,求x⊕y=1的期望值
这个显然就是a/n*b/n*2,问题是a和b该如何算 我们假设求a

那问题就又变成了求该区间有多少个数该位=1
要考虑限制的当前位=1/0的情况,
当前是被[]括起来的位
11100[0]101
假设为0
依旧分成两部分来看pre, suf
首先对于前面的pre的选择(0~11100-1),我们可以知道每一个都有23=111+1(0~2^3-1)个suf使得当前位为0,然后假如pre选11100,那么就只有suf+1个使得当前位为0(0~suf)

假设为1
那所有pre都可以取23(0~2^3-1)个suf为0

        if (bit[i]==0) {            ff=pre*mi[i-1]+suf+1;         } else {             ff=((pre+1)*mi[i-1]);        }

再乘上1-p和概率这样就可以计算出ans1,可以边加边除防止爆掉

第二部分就是求xf(x)
我们设fi,j,k表示第len~i位对答案的贡献,j,k分别表示x,f(x)下一次有没有限制
g[i,j,k]表示第i位的限制状态为j,k的数的个数.

枚举i,j,k,以及当前位选的x=0/1,我们知道有:
设现在要从i更新到i-1
当x有限制且x>a[i-1]显然这个不合法,舍去
我们判一下在现在的j,k的前提下,取x,!x是否会达到限制,也就是求新的j’,k’

然后再判,能否取!x做f(x)
如果k没限制,那么肯定能取!x,或者是没超过限制,那都可以取!x
如果能取那就有贡献,如果不能取那就没贡献

其实这里是有一种特殊情况的,!x>限制且k=1
但是看一下判断的条件
if (!k || bit[i-1]>!x) kk=0;
if (!k || bit[i-1]>=!x) toAns=mi[i-2]; else toAns=0;
然后能发现,如果是上述特殊情况的话,kk=1,这样其实就是无法取1接着取0的样子.

code

#include<cstdio>#include<cstdlib>#define fo(i,x,y) for(int i=x;i<=y;i++)using namespace std;long long n;double p, ans1, ans2, f[61][2][2];int bit[61];long long mi[61], g[61][2][2];int main() {    freopen("3442.in","r",stdin);    scanf("%lld %lf",&n,&p);    if (n==0) {printf("0.000000"); return 0;}    n--;    mi[0]=1;    for (int i=1; i<=60; i++) mi[i]=mi[i-1]*2;    bit[0]=0;    for (long long tmp=n; tmp>0; tmp/=2) bit[++bit[0]]=tmp%2;    long long a=n*n;    fo(i,1,bit[0]) {        long long pre=n/(mi[i]), suf=n%(mi[i]);        double ff = 0.0;        if (bit[i]==0) {            ff=pre*mi[i-1]+suf+1;         } else {             ff=((pre+1)*mi[i-1]);        }        double add=ff*(n+1-ff);        add/=(double)(n+1);        add/=(double)(n+1);        add*=mi[i-1]*(1-p);        ans1+=add;    }    ans1=ans1*2;    //part 2    f[bit[0]][0][1]=f[bit[0]][1][0]=mi[bit[0]-1];    g[bit[0]][0][1]=g[bit[0]][1][0]=1;    for (int i=bit[0]; i>0; i--)        fo(j,0,1)            fo(k,0,1)                if (g[i][j][k]) {                    fo(x,0,1) {                        if (j && (x>bit[i-1])) continue;                        long long jj=1,kk=1,toAns=0;                          if (!j || bit[i-1]>x) jj=0;                        if (!k || bit[i-1]>!x) kk=0;                        if (!k || bit[i-1]>=!x) toAns=mi[i-2]; else toAns=0;                        f[i-1][jj][kk]+=f[i][j][k]+toAns*g[i][j][k];                        g[i-1][jj][kk]+=g[i][j][k];                    }                }    ans2=0.0;    fo(j,0,1) fo(k,0,1) ans2+=f[1][j][k]*p/(double)(n+1);    double ans3=ans1+ans2;    int len=0;    if (ans3>=10) {        while (ans3>=10) {            len++;            ans3/=10;        }    } else     if (ans3<1 && ans3!=0){        while (ans3<1) {            ans3*=10;            len--;        }    }    //freopen("3442.out","w",stdout);    printf("%.8lf %d",ans3,len);    return 0; }
0 0
原创粉丝点击