[来源未知]卡片游戏

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

由表可得,一共有10种情况,其中有7种情况小W可以获得小礼物。因此小W获得小礼物的期望值是7/10。
【输入输出样例2】
game.in
4 1 4
3 1 2 4
game.out
1

【输入输出样例解释2】
由上表得,小W总是可以获得小礼物。因此期望值是1
【数据范围】
对于30%的数据,0 < n≤10,000;
对于70%的数据,0 < n≤100,000;
对于100%的数据,0 < n≤500,000,0 < l < r≤100。

sol:
方案数是…>=l的方案数减去…>r的方案数
(sum[j]-sum[i-1])/(j-(i-1))>=l
sum[j]-sum[i-1]>=j*l-(i-1)*l
(i-1)*l-sum[i-1]>=l*j-sum[j] 令a[i]=(i-1)*l-sum[i-1],求一下逆序对就行了
然后就再令b[i]=(i-1)*r-sum[i-1],答案相减就行啦

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=510000;
int n,m,l,r;
inline int read()
{
    char c;
    int res,flag=0;
    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
    res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
    return flag?-res:res;
}
int a[N],sum[N],b[N],val[N],t[N];
ll ans;
void solve(int l,int r)
{
    if(l>=r) return;
    int mid=l+r>>1;
    solve(l,mid);
    solve(mid+1,r);
    int i=l,j=mid+1,z=l;
    while(i<=mid&&j<=r)
    {
        if(a[i]>=a[j])
        {
            ans+=mid-i+1;
            t[z++]=a[j++];
        }
        else t[z++]=a[i++];
    }
    for(;i<=mid;++i) t[z++]=a[i];
    for(;j<=r;++j) t[z++]=a[j];
    for(int i=l;i<=r;++i)
    a[i]=t[i];
}
void solve2(int l,int r)
{
    if(l>=r) return;
    int mid=l+r>>1;
    solve2(l,mid);
    solve2(mid+1,r);
    int i=l,j=mid+1,z=l;
    while(i<=mid&&j<=r)
    {
        if(b[i]>b[j])
        {
            ans-=mid-i+1;
            t[z++]=b[j++];
        }
        else t[z++]=b[i++];
    }
    for(;i<=mid;++i) t[z++]=b[i];
    for(;j<=r;++j) t[z++]=b[j];
    for(int i=l;i<=r;++i)
    b[i]=t[i];
}
int gcd(ll x,ll y)
{
    return x%y?gcd(y,x%y):y;
}
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    n=read();
    l=read();
    r=read();
    for(int i=1;i<=n;++i)
    {
        val[i]=read();
        sum[i]=sum[i-1]+val[i];
    }
    for(int i=1;i<=n;++i)
    {
        a[i]=(i-1)*l-sum[i-1];
        b[i]=(i-1)*r-sum[i-1];
    }
    a[n+1]=n*l-sum[n];
    b[n+1]=n*r-sum[n];
    solve(1,n+1);
    solve2(1,n+1);
    ll total=(ll)n*(n+1)/2,GCD=gcd(total,ans);
    if(!ans)
    {
        printf("0");
        return 0;
    }
    ans/=GCD;
    total/=GCD;
    if(ans==total) printf("1");
    else printf("%lld/%lld",ans,total);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值