题目描述
小D举办了元旦联欢活动,其中有一个卡片游戏。
游戏的规则是这样的:有n张卡片,每张卡片上正面写着一个小于等于100的正整数ai,反面都是一样的花色。这n张卡片正面朝下叠成一堆,玩这个游戏的人从中可以抽出连续的k(1≤k≤n)张卡片。如果对于这k张卡片上的数字的平均值a,满足l<=a<=r,那他就可以获得小礼物一件。
小W来玩这个游戏了,她事先通过某些途径知道了这n张卡片上写的数字,现在她想知道她获得小礼物的期望值。
小W对小数很头疼,所以请你用分数的形式告诉她答案。
输入
输入文件名为game.in
输入第1行,三个整数n,l,r。
第2行,包含n个整数ai。
输出
输出文件名为game.out
输出仅1行,表示小W获得小礼物的期望值。输出格式为“P/Q”(P和Q互质)。如果期望值是0或1就不用输出分数了
样例输入
game.in
4 2 3
3 1 2 4
game.out
7/10
样例输出
【输入输出样例2】
game.in
4 1 4
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;
}