【問題描述】
有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;
}