【问题描述】
有N个数,随机选择一段区间,如果这段区间的所有数的平均值在[m,r]中则你比较厉害
求你比较厉害的概率
【输入格式】
第一行有三个数N,m,r,含义如上描述
接下来一行有N个数代表每一个数的值
【输出格式】
输出一行一个分数
如果答案为整数则直接输出该整数即可
【样例输入 1】
4 2 3
3 1 2 4
【样例输出 1】
7/10
【样例输入 2】
4 1 4
3 1 2 4
【样例输出 2】
1
【样例解释】
塔外面有棵树
【数据规模与约定】
60%的数据,1 ≤ N≤ 105
对于100%的数据,1 ≤ N ≤ 5× 105 ,0 < m≤ r≤ 100
现在是你比较强
没想到
是个
求逆序对
以下引用
要求 区间平均值>=l&&<=r 的个数
即
现在我们来求区间平均值在1~r的个数和1~l(不包括l)的个数 前减后即为所求
以求1~r为例
(a[i]+a[i+1]+……+a[i+k-1])/k<=r
(a[i]+a[i+1]+……+a[i+k-1])<=k*r
(a[i]+a[i+1]+……+a[i+k-1])-k*r<=0
(a[i]-r)+(a[i+1]-r)+……+(a[i+k-1]-r)<=0
令c[i]=a[i]-r得到一个新数组c
即求c数组区间和<=0的个数
令s为数组c的前缀和数组
c[i]+c[i+1]+…+c[i+k-1]<=0
s[i+k-1]-s[i]<=0
s[i+k-1]<=s[i]
则
i< i+k-1
s[i]>=s[i+k-1]
即求s数组逆序对数
引用结束
树状数组求逆序对
因为有负数
做了一点特殊处理
使它对应一个正数
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<vector>
#include<climits>
#include<string>
#include<cstdlib>
#include<ctime>
#define MOD 100000007
#define LL long long
using namespace std;
LL n,l,r,num[500005],s1[500005],s2[500005],b1[500005],b2[500005],pos,t1,t2,ans1,ans2,p,p1,p2,tmp,c[500005];
LL lowbit(LL x)
{
return x&(-x);
}
LL gcd(LL a,LL b)
{
if(!a) return b;
else return gcd(b%a,a);
}
LL getnum(LL x)
{
LL ans=0,i;
for(i=x;i>=1;i-=lowbit(i))
ans+=c[i];
return ans;
}
void add(LL x)
{
LL i;
for(i=x;i<=n;i+=lowbit(i)) c[i]++;
}
int main()
{
LL i;
scanf("%lld%lld%lld",&n,&l,&r);
for(i=1;i<=n;i++)
{
scanf("%lld",&num[i]);
s1[i]=num[i]-l+s1[i-1];
b1[i]=s1[i];
if(s1[i]<0) ans1++;
s2[i]=num[i]-r+s2[i-1];
b2[i]=s2[i];
if(s2[i]<=0) ans2++;
}
sort(s1+1,s1+n+1);
sort(s2+1,s2+n+1);
t1=unique(s1+1,s1+n+1)-s1-1;
t2=unique(s2+1,s2+n+1)-s2-1;
for(i=1;i<=n;i++)
{
pos=lower_bound(s1+1,s1+t1+1,b1[i])-s1;
b1[i]=pos;
pos=lower_bound(s2+1,s2+t2+1,b2[i])-s2;
b2[i]=pos;
}
for(i=n;i>=1;i--)
{
ans1+=getnum(b1[i]);
add(b1[i]+1);
}
memset(c,0,sizeof(c));
for(i=n;i>=1;i--)
{
ans2+=getnum(b2[i]);
add(b2[i]);
}
p1=ans2-ans1;
p2=(n*(n+1))/2;
tmp=gcd(p1,p2);
p1/=tmp;
p2/=tmp;
if(p1==p2) printf("1");
else printf("%lld/%lld",p1,p2);
return 0;
}