zoukankan      html  css  js  c++  java
  • AcWing216 Rainbow的信号 (期望)

    这道题要求的是贡献的平均值。

    直接计算挺难的,但是我们可以考虑按位枚举贡献,因为最多就30位,现在我们要知道的是,什么是贡献

    首先一共有n*n种取法,也就是最后求出来的数要除以n方

    那么我们分别来看三个函数的分子是什么,对于每一位,我们都枚举每个数当作右端点,之后寻找合法左端点就行了,这是常用的枚举所有情况的方法。

    因为我们现在已经拆分到位了,对于and,我们发现,如果右端点是0,那么没有答案,否则就是找到最近的一个0,在中间的都是合法的

    对于or来说,只要当前为是1,那么都是合法的,否则找到最近的1,在这之前的左端点都是合法的

    对于xor来说,我们要维护前缀和,只要和当前前缀和不同的,都是答案。

    注意的是,这个答案要*2,因为我们我们可以随意取左右端点,当左大于右的时候,翻转过来跟我们上面求的是一样的。

    但是有一点,如果左右端点相同,那只有一次,因此要先减去这种情况,之后*2,之后再把这种情况加回来

    还有一点,n*n爆int

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    int a[N],b[N][31];
    int s[N];
    long long n;
    double sxor(){
        double ans=0;
        int i,j;
        for(j=0;j<=30;j++){
            memset(s,0,sizeof s);
            int c[2]={1,0};
            for(i=1;i<=n;i++){
                s[i]=s[i-1]+b[i][j];
                ans+=(1ll<<j)*c[s[i]%2==0];
                c[s[i]%2]++;
            }
        }
        for(i=1;i<=n;i++)
        ans-=a[i];
        ans*=2;
        for(i=1;i<=n;i++)
        ans+=a[i];
        return ans/(n*n);
    }
    double sand(){
        double ans=0;
        int i,j;
        for(j=0;j<=30;j++){
            int last=0;
            for(i=1;i<=n;i++){
                if(b[i][j]){
                    ans+=(1ll<<j)*(i-last);
                }
                else{
                    last=i;
                }
            }
        }
        for(i=1;i<=n;i++)
        ans-=a[i];
        ans*=2;
        for(i=1;i<=n;i++)
        ans+=a[i];
        return ans/(n*n);
    }
    double sor(){
        double ans=0;
        int i,j;
        for(j=0;j<=30;j++){
            int last=0;
            for(i=1;i<=n;i++){
                if(b[i][j]){
                    ans+=(1ll<<j)*i;
                    last=i;
                }
                else{
                    ans+=(1ll<<j)*(last);
                }
            }
        }
        for(i=1;i<=n;i++)
        ans-=a[i];
        ans*=2;
        for(i=1;i<=n;i++)
        ans+=a[i];
        return ans/(n*n);
    }
    int main(){
        cin>>n;
        int i,j;
        for(i=1;i<=n;i++){
            cin>>a[i];
            int x=a[i];
            for(j=0;j<=30;j++){
                if((x>>j)&1)
                b[i][j]=1;
            }
        }
        printf("%.3f %.3f %.3f
    ",sxor(),sand(),sor());
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    优化!优化!
    JavaScript 错误
    js 学习总结
    JavaScript join() 方法
    JavaScript shift() 方法
    JavaScript split() 方法
    arTemplate解析语法
    getTime 方法
    PHP 5 数据类型
    thinkphp 实现微信公众号开发(二)--实现自定义菜单
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12707695.html
Copyright © 2011-2022 走看看