UVA 10288 - Coupons(数学期望+分数计算)

题目链接 https://cn.vjudge.net/problem/UVA-10288

【题意】
有n种不同的彩票,如果搜集齐所有的彩票就可以兑换大奖(n<=33)而每次买到的彩票种类是随机的,问你在平均情况下,需要买多少张彩票才能兑换大奖呢?用分数表示答案

【思路】
已经有 k k 种彩票,设 s=kn ,那么假设再买到一种新的彩票需要的次数为 t t 次,对应的概率为 st1(1s),所以平均需要的次数为

C(k)=t=1+st1(1s)t=(1s)t=1+st1t C ( k ) = ∑ t = 1 + ∞ s t − 1 ( 1 − s ) t = ( 1 − s ) ∑ t = 1 + ∞ s t − 1 t
然后用错位相减法,设
F(t)=t=1+st1t=1+2s+3s2+4s3+...... F ( t ) = ∑ t = 1 + ∞ s t − 1 t = 1 + 2 s + 3 s 2 + 4 s 3 + . . . . . .
sF(t)=t=1+stt=s+2s2+3s3+4s4+...... s F ( t ) = ∑ t = 1 + ∞ s t t = s + 2 s 2 + 3 s 3 + 4 s 4 + . . . . . .
F(t)sF(t)=1+s+s2+s3+...=limn+1sn+11s=11s F ( t ) − s F ( t ) = 1 + s + s 2 + s 3 + . . . = lim n → + ∞ 1 − s n + 1 1 − s = 1 1 − s
所以
F(t)=1(1s)2 F ( t ) = 1 ( 1 − s ) 2
C(k)=11s=nnk C ( k ) = 1 1 − s = n n − k
最后的结果即为
k=0n1C(k)=nk=0n11nk ∑ k = 0 n − 1 C ( k ) = n ∑ k = 0 n − 1 1 n − k

结果需要用分数表示,这里存一个分数计算的板子

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

long long __gcd(long long a,long long b){
    if(b==0) return a;
    return __gcd(b,a%b);
}

struct fraction {
    long long numerator;//分子
    long long denominator;//分母
    fraction() {
        numerator = 0;
        denominator = 1;
    }
    fraction(long long num) {
        numerator = num;
        denominator = 1;
    }
    fraction(long long a, long long b) {
        numerator = a;
        denominator = b;
        this->reduction();
    }

    void operator = (const long long num) {
        numerator = num;
        denominator = 1;
        this->reduction();
    }

    void operator = (const fraction &b) {
        numerator = b.numerator;
        denominator = b.denominator;
        this->reduction();
    }

    fraction operator + (const fraction &b) const {
        long long gcdnum = __gcd(denominator, b.denominator);
        fraction tmp = fraction(numerator*(b.denominator/gcdnum) + b.numerator*(denominator/gcdnum), denominator/gcdnum*b.denominator);
        tmp.reduction();
        return tmp;
    }

    fraction operator + (const int &b) const {
        return ((*this) + fraction(b));
    }

    fraction operator - (const fraction &b) const {
        return ((*this) + fraction(-b.numerator, b.denominator));
    }

    fraction operator - (const int &b) const {
        return ((*this) - fraction(b));
    }

    fraction operator * (const fraction &b) const {
        fraction tmp = fraction(numerator*b.numerator, denominator * b.denominator);
        tmp.reduction();
        return tmp;
    }

    fraction operator * (const int &b) const {
        return ((*this) * fraction(b));
    }

    fraction operator / (const fraction &b) const {
        return ((*this) * fraction(b.denominator, b.numerator));
    }

    void reduction() {
        if (numerator == 0) {
            denominator = 1;
            return;
        }
        long long gcdnum = __gcd(numerator, denominator);
        numerator /= gcdnum;
        denominator /= gcdnum;
    }
};

fraction a[50];

int main(){
    int n;
    while(scanf("%d",&n)==1){
        for(int i=1;i<=n;++i){
            a[i]=fraction(1,i);
        }
        for(int i=2;i<=n;++i){
            a[1]=a[1]+a[i];
        }
        a[1]=a[1]*n;
        long long x=a[1].numerator;
        long long y=a[1].denominator;
        if(y==1) printf("%lld\n",x);
        else{
            long long tmp=x/y,tmpy=y;
            int ctmp=0,cy=0;
            while(tmp){
                ++ctmp;
                tmp/=10;
            }
            while(tmpy){
                ++cy;
                tmpy/=10;
            }
            for(int i=0;i<=ctmp;++i) putchar(' ');
            printf("%lld\n",x%y);
            printf("%lld ",x/y);
            for(int i=0;i<cy;++i) putchar('-');
            puts("");
            for(int i=0;i<=ctmp;++i) putchar(' ');
            printf("%lld\n",y);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值