题意

题目描述

**记者弄了个大新闻,这个新闻是一个在 [0,n) 内等概率随机选择的整数,记其为 x。为了尽可能消除这个大新闻对公众造成的不良印象,我们需要在 [0,n)内找到某一个整数 y,使得 x ⊕ y 达到最大值。这里 ⊕ 代表异或。

问题在于,**记者有可能对大新闻进行了加密。情报显示,大新闻没有被加密的概率为 p。我们决定采取这样的策略:如果大新闻没有被加密,那么我们选出使得 x ⊕ y 最大的 y;否则,我们在 [0,n) 内等概率随机选择一个整数作为 y。

请求出 x ⊕ y 的期望值。

输入输出格式

输入格式:

输入文件仅包含一行,其中有一个正整数 n 和一个实数 p,含义如问题描述中所述。 p 至多精确到小数点后六位。

输出格式:

输出一行,代表 x ⊕ y 的期望值。只有当你的输出与标准输出的相对误差不超过 10−510^{-5}10−5 时,你的输出才会被判为正确。建议保留至少六位小数。

输入输出样例

输入样例#1:
复制

3 0.5
输出样例#1:
复制

2.000000
输入样例#2:
复制

123456 0.5
输出样例#2:
复制

98063.674346

说明

考虑样例一。如果大新闻没有被加密,那么可能的 x 与对应的 y 的取值如下:

此时的期望值为 8/3。

如果大新闻被加密了,那么可能的 x 和 y 的取值如下:

此时的期望值为 12/9 = 4/3。

所以总的期望值为 2。

所有测试点的数据规模如下:

对于全部测试数据,1≤n≤10181 \le n \le 10^{18}1≤n≤1018。

分析

参照[]

首先我们打一个i^j的表

我们发现,第一,这是一个关于对角线对称的(废话)

第二,对于任意一个从左上角开始,边长为2的幂的正方形(比如图中用白框框起来的),其下边和右边的边长为2的幂的正方形就是把这个正方形的每个元素加上这个2的幂

第三,对于任意一个从左上角开始,边长为2的幂的正方形,其右下的边长为2的幂的正方形和这个正方形是一样的

第四,对于从顶部开始,向下长度为2的幂的一列,0到2的幂-1的所有数都恰好出现一次

发现了这些规律之后我们看题,当p=1的时候,相当于求从第一列开始n列每列的最大值的和/n,p=0的时候,相当于求从左上角开始nn的正方形内所有元素的和/(nn)

当0<p<1时,只要把上边两个值加权加起来即可

先说如何求n*n的正方形的和

找到小于等于n的最大的2的幂的正方形,左上角的正方形可由规律4直接求出,右上的长方形可由规律2和规律4直接求出,由规律1左下的长方形和右上的长方形和是一样的,然后由规律3,我们可以递归求右下的正方形,这样复杂度是log的

在说如何求n列里每列最大值的和

找到小于n的最大的2的幂的正方形,由规律2和3,可知最大值一定在左下和右上,由规律4右上部分的可以直接求,然后我们递归左下的长方形

这样递归就有了3个变量x,y,u,x代表有多少行,y代表有多少列,u代表又规律2现在这个递归部分被加了多少值

在进行一次递归之后,y一定是2的幂

找到小于y的最大的2的幂xx,这里分两种情况讨论,若x>xx,即有左下部分,则算出右上然后递归左下,若x<=xx,即没有左下部分,由规律2我们递归左半边,然后右半边可以根据左半边的直接算出来

然后就好了

代码

其实要理解思路把代码和图结合起来看蛮清晰的。

但是他卡精度我是一点办法都没有,此题留坑吧。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;
    rg char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x){
    return x=read<T>();
}
typedef __int128 ll;
typedef long double ld;

class fraction{
private:
    ll numerator;//分子
    ll denominator;//分母
    ll gcd(ll x,ll y)const;//最大公约数
    ll lcm(ll x,ll y)const;//最小公倍数
    void fixup();//维护分母始终为正数 

public:
    //构造函数
    fraction();//缺省构造函数
    fraction(ll numerator); //分母默认值为1
    fraction(ll numerator,ll denominator);  

    //运算符重载
    friend const fraction operator +(const fraction &x,const fraction &y);
    friend const fraction operator -(const fraction &x,const fraction &y);
    friend const fraction operator *(const fraction &x,const fraction &y);
    friend const fraction operator /(const fraction &x,const fraction &y);
    const fraction operator -();

    const fraction simplify()const; //化简
    const fraction reciprocal()const;//倒数 

    friend bool operator >(const fraction &x,const fraction &y);
    friend bool operator >=(const fraction &x,const fraction &y);
    friend bool operator <(const fraction &x,const fraction &y);
    friend bool operator <=(const fraction &x,const fraction &y);
    friend bool operator !=(const fraction &x,const fraction &y);
    friend bool operator ==(const fraction &x,const fraction &y);
    fraction& operator =(const fraction &x);
    //输出
    ld print()const;
};

//用初始化列表写构造函数
fraction::fraction(ll x,ll y):numerator(x),denominator(y){
    assert(y!=0);//确保分母不为0,否则在运行过程中报错
}

fraction::fraction(ll x):numerator(x),denominator(1){ }

fraction::fraction(){ }

//最小公倍数
ll fraction::lcm(ll x,ll y)const
{
    //欧几里得算法
    while(y){
        ll t=y;
        y=x%y;
        x=t;
    }
    return x;
} 

//最大公约数
ll fraction::gcd(ll x,ll y)const
{
    ll n=lcm(x,y);
    return x*y/n;
}

//维护分母为正
void fraction::fixup()
{
    //如果分母为负,将分子分母同时取负
    if(denominator<0){
        denominator=-denominator;
        numerator=-numerator;
    }
    assert(denominator!=0);
}

//化简
const fraction fraction::simplify()const
{
    fraction ans;
    ll n=lcm(numerator,denominator);//得到最小公倍数
    ans.denominator=denominator/n;//分子分母同时除以最小公倍数
    ans.numerator=numerator/n;
    return ans;
}

const fraction operator +(const fraction &x,const fraction &y)
{
    ll n=x.gcd(x.denominator,y.denominator);//得到最大公约数
    fraction ans;
    //将分母化为相同的再对分子进行加法运算
    ans.numerator=n/x.denominator*x.numerator+n/y.denominator*y.numerator;
    ans.denominator=n;
    return ans.simplify();
}

const fraction operator -(const fraction &x,const fraction &y)
{
    ll n=x.gcd(x.denominator,y.denominator);//得到最大公约数
    fraction ans;
    //将分母化为相同的再对分子进行减法运算
    ans.numerator=n/x.denominator*x.numerator-n/y.denominator*y.numerator;
    ans.denominator=n;
    return ans.simplify();
}

const fraction operator *(const fraction &x,const fraction &y)
{
    fraction ans;
    fraction tmp_x=x.simplify();
    fraction tmp_y=y.simplify();
    //分子分母对应相乘
    ans.numerator=tmp_x.numerator*tmp_y.numerator;
    ans.denominator=tmp_x.denominator*tmp_y.denominator;
    return ans.simplify();
}

const fraction operator /(const fraction &x,const fraction &y)
{
    fraction ans;
    fraction tmp_x=x.simplify();
    fraction tmp_y=y.simplify();
    assert(tmp_y.denominator!=0);//分子为0不能作为除数
    //分子乘分母,分母乘分子
    ans.numerator=tmp_x.numerator*tmp_y.denominator;
    ans.denominator=tmp_x.denominator*tmp_y.numerator;
    ans=ans.simplify();
    ans.fixup();
    return ans;
}

const fraction fraction::operator -()
{
    //分子变为相反数
    fraction x;
    x.numerator=-numerator;
    x.denominator=denominator;
    return x;
}

fraction& fraction::operator =(const fraction &x)
{
    if(this!=&x){
        numerator=x.numerator;
        denominator=x.denominator;
    }
    return *this;
}
bool operator >(const fraction &x,const fraction &y)
{
    if((x-y).numerator>0)return true;
    else return false;
}

bool operator >=(const fraction &x,const fraction &y)
{
    if((x-y).numerator>=0)return true;
    else return false;
}

bool operator <(const fraction &x,const fraction &y)
{
    if((x-y).numerator<0)return true;
    else return false;
}

bool operator <=(const fraction &x,const fraction &y)
{
    if((x-y).numerator<=0)return true;
    else return false;
}

bool operator !=(const fraction &x,const fraction &y)
{
    if((x-y).numerator!=0)return true;
    else return false;
}

bool operator ==(const fraction &x,const fraction &y)
{
    if((x-y).numerator==0)return true;
    else return false;
}

const fraction fraction::reciprocal()const
{
    return 1/(*this);
}

ld fraction::print()const
{
    return (ld)numerator/denominator;
}

ll n;
ld p;
ll low(ll x){
    ll t=1;
    for(;t<=x;t<<=1);
    return t>>1;
}
fraction sum(ll x,ll y){
    return fraction(x+y)*(y-x+1)/2;
}
fraction cal2(ll x){
    if(x<=1) return 0;
    ll xx=low(x);
    return sum(0,xx-1)*xx+sum(xx,xx+xx-1)*(x-xx)*2+cal2(x-xx);
}
fraction cal1(ll x,ll y,ll u){
    if(!x||!y) return 0;
    if(y==1) return u;
    ll xx=low(y-1);
    if(x>xx) return (u+xx*2-1)*(y-xx)+cal1(x-xx,xx,u+xx);
    return cal1(x,xx,u)*2+xx*xx;
}
int main(){
//  freopen(".in","r",stdin),freopen(".out","w",stdout);
    read(n);
    scanf("%Lf",&p);
    printf("%Lf\n",p*cal1(n,n,0).print()/n+(1-p)*cal2(n).print()/n/n);
    return 0;
}

正解

很久以前,某出题人给我们考了一套题,里面就有。

这并不是古典概型……

LG3898 [湖南集训]大新闻的更多相关文章

  1. 大新闻!HoloLens即将入华商用

    昨天微软搞了大新闻,Terry和Alexi到了深圳,在WinHEC大会上宣布了2017上半年HoloLens正式入华商用. 关于HoloLens的技术原理和细节官方文档和报道已经披露很多了,他是一款真 ...

  2. 主席树 || 可持久化线段树 || BZOJ 3653: 谈笑风生 || Luogu P3899 [湖南集训]谈笑风生

    题面:P3899 [湖南集训]谈笑风生 题解: 我很喜欢这道题. 因为A是给定的,所以实质是求二元组的个数.我们以A(即给定的P)作为基点寻找答案,那么情况分两类.一种是B为A的父亲,另一种是A为B的 ...

  3. [BZOJ 3652]大新闻

    [BZOJ 3652] 大新闻 题意 随机从 \([0,n)\) 中选取一个整数 \(x\), 并从 \([0,n)\) 中再选取一个整数 \(y\). 有 \(p\) 的概率选取一个能令 \(x\o ...

  4. P3900 [湖南集训]图样图森破

    P3900 [湖南集训]图样图森破 链接 分析: 感觉像个暴力. 可以枚举回文串的回文中心,即枚举一个串,枚举一个串的位置作为回文中心,然后求出这个串内的回文串的长度. 此时如果回文串两端都没有到这个 ...

  5. 【python】10分钟教你用python一行代码搞点大新闻

    准备 相信各位对python的语言简洁已经深有领会了.那么,今天就带大家一探究竟.看看一行python代码究竟能干些什么大新闻.赶紧抄起手中的家伙,跟我来试试吧. 首先你得先在命令行进入python. ...

  6. [CSP-S模拟测试]:大新闻(主席树)

    题目传送门(内部题20) 输入格式 第一行为两个数$n,m$,意义如题所述.接下来一行$n$个数,代表一开始$n$条大新闻的$naive$值.接下来$m$行,每行一个操作,输入格式如下:读入$1$,代 ...

  7. 几年前的今天,Google发了这几篇“大”新闻

    免责声明: 因阅读本文所导致的任何时间或经济上的损失,皆由您自行承担,本小编概不负责. 估计今天我的朋友圈会被"震惊!"刷屏,来看看 Google 做过哪些令人"震惊&q ...

  8. 湖南集训day2

    难度:☆☆ /*显然可以前缀和*/ #include<iostream> #include<cstdio> #include<cstring> #define N ...

  9. CDQZ 集训大总结

    好爆炸的一次集训…… 成绩: 什么鬼, 烂到一定地步了. 在这里每天考试80%都是暴力,正解思维难度的确比之前大了很多,考的范围也扩大了,比起之前的单独考一个知识点,转变为了多知识点多思维的综合,见了 ...

随机推荐

  1. 新视觉影院yy6080.org视频的抓取

    用fiddler 分析了一下, 从点连接 到 视频播放的过程 http://yy6080.org/v/103390 http://id.jiathis.com/id.php?u=http%3A%2F% ...

  2. CF576E Painting Edges

    首先,有一个很暴力的nk的做法,就是对每种颜色分别开棵lct来维护. 实际上,有复杂度与k无关的做法. 感觉和bzoj4025二分图那个题的区别就在于这个题是边dfs线段树边拆分区间.

  3. Travelling Salesman and Special Numbers CodeForces - 914C (数位dp)

    大意: 对于一个数$x$, 每次操作可将$x$变为$x$二进制中1的个数 定义经过k次操作变为1的数为好数, 求$[1,n]$中有多少个好数 注意到n二进制位最大1000位, 经过一次操作后一定变为1 ...

  4. 『PyTorch』第一弹_静动态图构建if逻辑对比

    对比TensorFlow和Pytorch的动静态图构建上的差异 静态图框架设计好了不能够修改,且定义静态图时需要使用新的特殊语法,这也意味着图设定时无法使用if.while.for-loop等结构,而 ...

  5. thinkphp %s %d %f

    %s -- 表示字段串%d -- 表示整形数字%f -- 表示浮点数 例子:$order_number = $m_ebay_order_numbers->where("ebay_ord ...

  6. IntelliJ IDEA 自动导入包 快捷方式 关闭重复代码提示

    idea可以自动优化导入包,但是有多个同名的类调用不同的包,必须自己手动Alt+Enter设置 设置idea导入包 勾选标注 1 选项,IntelliJ IDEA 将在我们书写代码的时候自动帮我们优化 ...

  7. POJ 3481 treap

    这是利用treap写的二叉排序树,只要理解其中旋转能够改变树的左右子树平衡度,即高度之差,差不多就能掌握treap树的要领了. 相对于其他高级BST,treap树实现应该算最简单了,利用的是随机树产生 ...

  8. 进程通信方式-管道pipe

    管道是两个进程间进行单向通信的机制.因为管道传递数据的单向性,管道又称之为半双工管道. 1.数据只能从一个进程流向另一个进程(其中一个写管道,另一个读管道):如果要进行全双工通信,需要建立两个管道. ...

  9. ReactJS环境搭建

    1.ReactJs 需要依赖nodejs环境,如果没有安装nodejs的话,需要安装.下载地址:https://nodejs.org/en/download/ 下载下来之后,安装windows版本的m ...

  10. idea开发工具安装说明

    开发工具安装说明   安装JDK1.8 第一步,双击"jdk-8u45-windows-i586.exe"安装文件,进行安装,具体安装过程如下图所示: 第二步,右键我的电脑-属性- ...