zoukankan      html  css  js  c++  java
  • 【NOIP模拟】区间平均值

    题面

    有 N 个数,随机选择一段区间,如果这段区间的所有数的平均值在[l, r]中则你比较厉害。求你比较厉害的概率。

    输入格式:

    第一行有三个数 N, l, r,含义如上描述。接下来一行有 N 个数代表每一个数的值。

    输出格式:

    输出一行一个分数 a/b 代表答案,其中 a, b 互质。 如果答案为整数则直接输出该整数即可。
    样例输入 1:
    4 2 3
    3 1 2 4
    样例输出 1:
    7/10
    样例输入 2:
    4 1 4
    3 1 2 4
    样例输出 2:
    1
    数据规模与约定:
    对于 30%的数据, 1 ≤ N ≤ 104
    对于 60%的数据, 1 ≤ N ≤ 105
    对于 100%的数据, 1 ≤ N ≤ 5 × 105 ,0 < l ≤ r ≤ 100。

    分析

     求平均数在[l,r]等价于求平均数在[1,l)和[1,r]的区间数量,后者减去前者即答案

    怎么维护??

    以区间[i,k]≤r的平均数为例,如果平均数比r小,那么每个数减去r后求和的值一定≤0

    即 a[i]-r+a[i+1]-r+a[i+2]-r+·······+a[i+k-1]-r≤0

    r是常数,假设b[i]=a[i]-r,则b[i]+b[i+1]+······+b[i+k-1]≤0

    看到b数组在求和,很容易联想到维护b数组的前缀和s[]

    b[i]+b[i+1]+······+b[i+k-1]=s[i+k-1]-s[i-1].可得s[i+k-1]-s[i-1]≤0

    所以,s[i+k-1]≤s[i-1],又因为i-1≤i+k-1,序号更靠前,值却更大,有多少个平均数≤r的区间,就是s[]序列的逆序对有多少对,对于l同理,只不过≤需要改为<。

    所以我们只需要求出两组逆序对,就求出了两个区间的数量,再相减。

    防止数组编号为负以及数字过大,用了基础的离散化。还需要注意开闭区间的问题,l是开区间,是求严格的逆序对,r是开区间,是求不严格的(可以包括本身)

    #include<bits/stdc++.h>
    using namespace std;
    #define N 600000
    #define ll long long
    ll n,l,r,fz,fm,nx1,nx2,mx1,mx2,gcd;
    ll a[N],b[N],c[N],d[N],sum1[N],sum2[N],g[N];
    inline ll lowbit(ll x)
    {
        return x&(-x);
    }
    inline void add(ll x)
    {
        for(;x<=n;x+=lowbit(x))
            g[x]++;
    }
    inline ll query(ll x)
    {
        ll ret=0;
        for(;x;x-=lowbit(x))
            ret+=g[x];
        return ret;
    }
    
    int main()
    {
        scanf("%lld%lld%lld",&n,&l,&r);
        for(ll i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            sum1[i]=sum1[i-1]+a[i]-r;
            sum2[i]=sum2[i-1]+a[i]-l;
            c[i]=sum1[i];d[i]=sum2[i];
            if(sum1[i]<=0)nx1++;//与s[0]比较 ,区间[1,i]的平均值<=r 
            if(sum2[i]<0)nx2++;//与 s[0]比较,区间[1,i]的平均值<l 
        }
        sort(c+1,c+1+n);sort(d+1,d+1+n);
        mx1=unique(c+1,c+1+n)-(c+1);mx2=unique(d+1,d+1+n)-(d+1);
        for(ll i=1;i<=n;i++)
        {
            sum1[i]=lower_bound(c+1,c+1+mx1,sum1[i])-c;
            sum2[i]=lower_bound(d+1,d+1+mx2,sum2[i])-d;
        }
        for(ll i=n;i;i--)
        {
            nx1+=query(sum1[i]);//不严格的逆序对 
            add(sum1[i]);
        }
        memset(g,0,sizeof(g));
        for(ll i=n;i;i--)
        {
            nx2+=query(sum2[i]-1);
            add(sum2[i]); 
        }
        fz=nx1-nx2;fm=(1+n)*n/2;gcd=__gcd(fz,fm);
        if(fz==fm)printf("1");
        else printf("%lld/%lld",fz/gcd,fm/gcd);
    }
    “Make my parents proud,and impress the girl I like.”
  • 相关阅读:
    Java字符串(String类)
    Java异常处理
    Scanner使用方法
    OOP之重载
    构造函数和析构函数
    类、对象、方法
    函数
    数组
    ahk之路:利用ahk在window7下实现窗口置顶
    指针的问题
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9549434.html
Copyright © 2011-2022 走看看