zoukankan      html  css  js  c++  java
  • codevs 1516 平均分数 【数学推理+求逆序对】

    题目:
        X学校被抽中进行一次数学测验,该学校共有N人,每个人有一个学号,一号学生的学号是1...N号学生的学号是N.
       为了减轻统计的负担,该学校只会随机抽取学号连续的k人(1≤k≤n),且将该k人的平均分统计出来。小明已经知道了所有人的成绩,小明想知道,平均分在[L,R]上的概率为多少。

    【数据范围】

    对于30%的数据,N≤10,000

    对于100%的数据,N≤1,000,000

    没错,它绿了;

    分析:

    如果直接暴力用区间枚举,即使用前缀和优化,复杂度依然是O(N^2),会超时。但如果尝试以下数学推理,问题会发生微妙的变化:

    L <= (sum[i]-sum[j]) / (i-j) <= R   ===> tot;(数目)

    L <= (sum[i]-sum[j]) / (i-j) ===> L*i-sum[i] <= L*j-sum[j] ===> ans1;(数目)

    R < (sum[i]-sum[j]) / (i-j) ===> R*i-sum[i] < R*j-sum[j] ===> ans2;(数目)

    易得:tot = ans1-ans2;

    注意红色的部分,可以发现他们可以经过专门处理而变成新的数组A,B,接下来我们要做的就是去求数组中的逆序对了。

    求逆序对有三种思路:

    线段树,树状数组,归并排序;

    因为此题中对于L 和 R ,逆序对分别可以和不可以取等,所以用树状数组不好处理,所以只好用归并排序。

    注意:当红色的式子中j取1时,需要A[0]和B[0],因此A[0]和B[0]也是序列中的一部分(虽然是0),它蕴含着所有包含1的逆序对的信息,因此算逆序对时要从(0,N)开始。

    下面是参考代码:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    long long a[1000010],sum[1000010],tot=0;
    long long n,L,R;
    bool flag=1;
    long long AA[1000010],BB[1000010];
    long long temp[1000010]={0};
    void mergesort(long long l,long long r,long long f[])
    {
     if(l==r) return;
     long long mid=(l+r)/2;
     mergesort(l,mid,f);
     mergesort(mid+1,r,f);
     long long i=l,p=l,j=mid+1;
     while(i<=mid&&j<=r)
     {
      if(f[i]>f[j] || (f[i]==f[j])*flag)
      {
       temp[p++]=f[j++]; 
       tot+=mid-i+1;
      }
      else
       temp[p++]=f[i++];
     }
     while(i<=mid) temp[p++]=f[i++];
     while(j<=r) temp[p++]=f[j++];
     for(int i=l;i<=r;i++)
      f[i]=temp[i];
    }
    long long gcd(long long x,long long y)
    {
     while(x)
     {
      int temp=y%x;
      y=x;
      x=temp;
     }
     return y;
    }
    int main()
    {
     cin>>n>>L>>R;
     for(long long i=1;i<=n;i++)
     {
      cin>>a[i];
      sum[i]=sum[i-1]+a[i];
     }
     for(long long i=0;i<=n;i++)
     {
      AA[i]=L*i-sum[i];
      BB[i]=R*i-sum[i];
     }
     long long ans1=0,ans2=0;
     mergesort(0,n,AA);
     ans1=tot,tot=0;
     flag=0;
     mergesort(0,n,BB);
     ans2=tot;
     tot=ans1-ans2;
     long long cnt=n*(n+1)/2;
     if(cnt==tot)
      cout<<1;
     else if(tot==0)
      cout<<0;
     else
     {
      long long tt=gcd(tot,cnt);
      printf("%lld/%lld",tot/tt,cnt/tt);
     }
     return 0;
    }
    View Code
  • 相关阅读:
    WMware 10 Ubuntu 12.04 进入Unity模式
    Spring+Struts集成(第二种方案)
    strut1.X和spring整合的二种方法
    Struts+Spring+Hibernate的Web应用执行过程
    Hibernate配置文件中配置各种数据库的driver、URL
    连接Oracle数据库的Hibernate配置文件
    Hibernate SQL 方言(hibernate.dialect)
    HibernateUtil.java
    hibernate里的generator中class =value介绍
    Hibernate的generator属性
  • 原文地址:https://www.cnblogs.com/linda-fcj/p/7206236.html
Copyright © 2011-2022 走看看