1. 程式人生 > >P1291 [SHOI2002]百事世界盃之旅 (期望)

P1291 [SHOI2002]百事世界盃之旅 (期望)

題意:

中文不解釋了

分析:

假設f(n,k)表示一共有n個球星,現在還剩k個未收集到,還需購買飲料的平均次數。

那麼要求的就是f(n,n)

假設我們現在推到了f(n,k),我們再買一瓶飲料,有兩種可能性,一種是:我們買到了我們沒有擁有的球員,那麼剩下的子問題就是f(n,k-1);如果買到了我們擁有的球員,那麼剩下的子問題就是f(n,k)。然而我們任意買一個瓶蓋,有\frac{k}{n}的可能性買到我們沒有的,有\frac{n-k}{n}的可能性買到我們已經有的。所以這道題目的遞推是就是:  

f(n,k)=\frac{(n-k)f(n,k)}{n}+\frac{kf(n,k-1)}{n}+1

化簡得:

f(n,k)=f(n,k-1)+\frac{k}{n}                                           

#include<cstdio>
#include<cstring>

using namespace std;

typedef long long ll;

inline ll gcd(ll a,ll b){
    if(b==0) return a;
    else return gcd(b,a%b);
}

inline int dig_len(ll a){
    int ans=0;
    while(a){
        ans++;
        a/=10;
    }
    return ans;
}

int main(){
    int n;
    ll p=0,q=1,r;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        p=p*i+q*n;
        q*=i;
        ll f=gcd(p,q);
        p/=f;q/=f;
    }
    r=p/q;
    p=p%q;
    if(p==0){
        printf("%lld\n",r);
    }else{
        for(int i=dig_len(r);i>0;i--){
            printf(" ");
        }
        printf("%lld\n",p);
        if(r) printf("%lld",r);
        for(int i=dig_len(q);i>0;i--){
            printf("-");
        }
        printf("\n");
        for(int i=dig_len(r);i>0;i--){
            printf(" ");
        }
        printf("%lld\n",q);
    }
    return 0;
}