[未完待续][NOI2017模拟]大新闻

题目背景
2016.05.19 T1

题目描述
记者弄了个大新闻,这个新闻是一个在 [0,n) 内等概率随机选择的整数,记其为 x 。为了尽可能消除这个大新闻对公众造成的不良印象,我们需要在 [0,n) 内找到某一个整数 y ,使得 x⊕y 达到最大值。这里 ⊕ 代表异或。
问题在于,记者有可能对大新闻进行了加密。情报显示,大新闻没有被加密的概率为 p 。我们决定采取这样的策略:如果大新闻没有被加密,那么我们选出使得 x⊕y 最大的 y ;否则,我们在 [0,n) 内等概率随机选择一个整数作为 y 。
请求出 x⊕y 的期望值。

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

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

样例数据1
输入
3 0.5
输出
2.000000
样例数据2
输入
123456 0.5
输出
98063.674346

备注
【样例解释】
考虑样例一。如果大新闻没有被加密,那么可能的 x 与对应的 y 的取值如下:
这里写图片描述
此时的期望值为 8/3。
如果大新闻被加密了,那么可能的 x 和 y 的取值如下:
这里写图片描述
此时的期望值为 12/9 = 4/3。
所以总的期望值为 2 。

【数据规模与约定】
所有测试点的数据规模如下:
这里写图片描述
对于全部测试数据,1≤n≤10^18。

分析: 50%:对于前十个点p=0或1十分有特殊性,n<=100时,不妨直接暴力;n=2^k时,若p=0,期望为(2^k-1)/2,若p=1,期望为2^k-1,这两个是很好推的;至于后面的大数据,不妨做一名mo法师[滑稽。
100%:暂时看着吧……(假装看懂了的样子)
这里写图片描述
代码:
50%(本人考场作)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;

int getint()
{
    int sum=0,f=1;
    char ch;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;ch>='0'&&ch<='9';ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

long long getlong()
{
    long long sum=0,f=1;
    char ch;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-')
    {
        f=-1;
        ch=getchar();
    }
    for(;ch>='0'&&ch<='9';ch=getchar())
        sum=(sum<<3)+(sum<<1)+ch-48;
    return sum*f;
}

const double eps=0.000000001;
int mx[110];
bool bj;
long long n,ans1,mi[65];
double ans;
double p;

int main()
{
    freopen("news.in","r",stdin);
    freopen("news.out","w",stdout);

    n=getlong();p=getint();
    mi[0]=1;
    if(n==mi[0])
    {
        bj=1;
        ans1=mi[0];
    }
    for(int i=1;i<=60;++i)
    {
        mi[i]=(mi[i-1]<<1);
        if(n==mi[i])
        {
            bj=1;
            ans1=mi[i];
        }
    }

    if(fabs(p-1)<eps)
    {
        if(bj==1)
        {
            printf("%I64d.000000\n",ans1-1);
            return 0;
        }
        else
            if(n<=100)
            {
                for(int i=0;i<n;++i)
                    for(int j=0;j<n;++j)
                        if((i^j)>mx[i])
                            mx[i]=(i^j);

                for(int i=0;i<n;++i)
                    ans+=mx[i];

                ans=ans*1.0/n;
                printf("%0.6f\n",ans);
                return 0;
            }
            else//n<=10^18
            {
                printf("19260817.192608\n");//-1s[滑稽
                return 0;
            }
    }
    else
        if(fabs(p-0)<eps)
        {
            if(n<=100)
            {
                for(int i=0;i<n;++i)
                    for(int j=0;j<n;++j)
                        ans+=(i^j);

                ans=ans*1.0/(n*n);
                printf("%0.6f\n",ans);
                return 0;
            }
            else
                if(bj==1)
                {
                    ans1=(n-1)/2;
                    printf("%I64d.500000\n",ans1);
                    return 0;
                }
                else//n<=10^18
                {
                    printf("19260817.192608\n");//-2s[滑稽
                    return 0;
                }
        }
        else//0<=p<=1
        {
            printf("19260817.192608\n");//-3s[滑稽
            return 0;
        }
    return 0;
}

100%(膜hyj大佬orz,就他一个AC了),暂时看着吧……(继续假装看懂了的样子)

#include <bits/stdc++.h>
using namespace std;
long long n;
double p;
double ans1, ans2, pi[65], ans;
long long pow1[65];
int bit[65], cnt;
long double f[65][2][2], g[65][2][2];
int main () {
    cin >> n;
    cin >> p;
    pow1[0] = 1;
    for (int i = 1; i <= 62; ++i) {
        pow1[i] = pow1[i - 1] * 2;
    }
    int up = log2(n);
    cout << setiosflags(ios::fixed) << setprecision(6);
//  cout<<"up = "<<up<<'\n';
    for (long long i = 0; i <= up; ++i) {
        pi[i] = ((double)(n / pow1[i + 1]) * pow1[i] + (double)max(n % pow1[i + 1] - pow1[i], 0ll)) / n;
//      printf("pi[%d] = ",i);
        //  cout<< pi[i]<<'\n';
    }
    for (int i = 0; i <= up; ++i) {
        ans1 += 2 * pi[i] * (1 - pi[i]) * pow1[i];
    }
    long long t = n - 1;
    for (; t; t >>= 1)bit[++cnt] = t & 1;
    f[cnt][0][1] = f[cnt][1][0] = pow1[cnt - 1];
    g[cnt][0][1] = g[cnt][1][0] = 1;
    int nxtj, nxtk;
    long long nxtans;
    for (int i  = cnt ; i ; --i) {
        for (int j = 0 ; j < 2; ++j) {
            for (int k = 0; k < 2; ++k) {
                if (g[i][j][k])
                for (int x = 0; x < 2; ++x) {
                    if (j && (x > bit[i - 1])) continue;
                    nxtj = 1, nxtk = 1;
                    nxtans = 0;
                    if (!j || x < bit[i - 1])nxtj = 0;
                    if (!k || !x < bit[i - 1]) nxtk = 0;
                    if (!k || !x <= bit[i - 1]) nxtans = pow1[i - 2] ; else nxtans = 0;
                    f[i - 1][nxtj][nxtk] += f[i][j][k] + g[i][j][k] * nxtans;
                    g[i - 1][nxtj][nxtk] += g[i][j][k] ;
                }
            }
        }
    }
    for (int i = 0 ; i < 2; ++i) {
            for (int j = 0; j < 2; ++j) {
            //  printf("f[%d][%d][%d] = %lf\n", k, i, j, (double)f[k][i][j]);
                ans2 += (long double)f[1][i][j] * p / (long double)n;
            }
        }
    ans += ans1 * (1 - p) + ans2;
    cout << ans << '\n';
}

本题结?No!No!No!没弄懂怎么能叫结呢?

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值