卡片游戏(逆序对)

来源:互联网 发布:单晶和多晶冰糖 知乎 编辑:程序博客网 时间:2024/05/01 19:09

题目描述

小D举办了元旦联欢活动,其中有一个卡片游戏。

游戏的规则是这样的:有n张卡片,每张卡片上正面写着一个小于等于100的正整数ai,反面都是一样的花色。这n张卡片正面朝下叠成一堆,玩这个游戏的人从中可以抽出连续的k(1≤kn)张卡片。如果对于这k张卡片上的数字的平均值a,满足l<=a<=r,那他就可以获得小礼物一件。

小W来玩这个游戏了,她事先通过某些途径知道了这n张卡片上写的数字,现在她想知道她获得小礼物的期望值。

小W对小数很头疼,所以请你用分数的形式告诉她答案。

输入

输入文件名为game.in

输入第1行,三个整数nlr

第2行,包含n个整数ai

输出

输出文件名为game.out

输出仅1行,表示小W获得小礼物的期望值。输出格式为“P/Q”(PQ互质)。如果期望值是01就不用输出分数了

样例输入

game.in  
4 2 3 
3 1 2 4 
game.out
7/10

样例输出

【输入输出样例2】
game.in  
4 1 
3 1 2 4  
game.out
1

提示

【输入输出样例解释1】


 


































































【输入输出样例解释1】抽出的卡片


a(保留2位小数)


是否满足l<=a<=r


 


3


3.00



 


1


1.00


2


2.00



 


4


4.00


3,1


2.00



 


1,2


1.50


2,4


3.00



 


3,1,2


2.00



 


1,2,4


2.33



 


3,1,2,4


2.50



 


 【输入输出样例解释2】


由上表得,小W总是可以获得小礼物。因此期望值是1


 


【数据范围】


对于30%的数据,0<n≤10,000;


对于70%的数据,0<n≤100,000;


对于100%的数据,0<n≤500,000,0<l<r≤100。


由表可得,一共有10种情况,其中有7种情况小W可以获得小礼物。因此小W获得小礼物的期望值是7/10。


solution:首先,容易想到用前缀和s[i]表示,j+1到i的平均数就是(s[i]-s[j])/(i-j)    (0<=j<i<=n),由题意得,要求l<=(s[i]-s[j])/(i-j)<=r的次数,要同时满足两个约束,这个不好处理,我们可以先考虑l<=(s[i]-s[j])/(i-j)的次数,再减去(s[i]-s[j])/(i-j)<r的次数,注意,是<r不是<=r+1,这里不一样的,

先来看左边,l<=(s[i]-s[j])/(i-j)  <=>  l*(i-j)<=s[i]-s[j]  <=>  s[j]-l*j<=s[i]-l*i  这样子就比较明显了——逆序对,准确地说是顺序对,用归并排序,时间复杂度θ(n lg n)

同理,在做一个s[i]-r*i的顺序对,这个要把等于的去掉。 

最好把第一个个数减去第二个个数,就是满足的次数。总次数是n*(n+1)/2,约分一下就解决了。

细节见代码:

#include<iostream>  #include<cstdio>  #include<cmath>  #include<algorithm>  #include<cstdlib>  #include<cstring>  using namespace std;  int k1,k2;  long long n,ans1,ans2,ans,fm,yf,a[1000000],s[1000000],b[1000000],c[1000000],q[1000000],ll,rr;  void ms(int l,int r){      if(l==r)          return;      int mid=(l+r)>>1;      ms(l,mid);      ms(mid+1,r);      k1=l;      k2=mid+1;      while(k1<=mid&&k2<=r){          if(b[k1]<=b[k2]){              ans1+=(long long)(r-k2+1);              q[k1-l+k2-mid]=b[k1];              k1++;          }          else{              q[k1-l+k2-mid]=b[k2];              k2++;          }      }      while(k1<=mid){          q[k1-l+k2-mid]=b[k1];          k1++;      }      while(k2<=r){          q[k1-l+k2-mid]=b[k2];          k2++;      }      for(int i=l;i<=r;i++)          b[i]=q[i-l+1];  }  void ms1(int l,int r){      if(l==r)          return;      int mid=(l+r)>>1;      ms1(l,mid);      ms1(mid+1,r);      k1=l;      k2=mid+1;      while(k1<=mid&&k2<=r){          if(c[k1]<c[k2]){              ans2+=(long long)(r-k2+1);              q[k1-l+k2-mid]=c[k1];              k1++;          }          else{              q[k1-l+k2-mid]=c[k2];              k2++;          }      }      while(k1<=mid){          q[k1-l+k2-mid]=c[k1];          k1++;      }      while(k2<=r){          q[k1-l+k2-mid]=c[k2];          k2++;      }      for(int i=l;i<=r;i++)          c[i]=q[i-l+1];  }  long long gcd(long long x,long long y){      if(x==0)          return y;      return gcd(y%x,x);  }  int main(){      scanf("%d%lld%lld",&n,&ll,&rr);      for(int i=1;i<=n;i++){          scanf("%lld",&a[i]);          s[i]=s[i-1]+a[i];          b[i]=s[i]-ll*i;          c[i]=s[i]-rr*i;      }      ms(0,n);      ms1(0,n);      ans=ans1-ans2;      fm=n*(n+1)/2;      yf=gcd(ans,fm);      ans/=yf;      fm/=yf;      if(ans==0)          printf("0\n");      else    if(ans==fm)          printf("1\n");      else        printf("%lld/%lld\n",ans,fm);      return 0;  } 


原创粉丝点击