1. 程式人生 > >【SHOI 2002】百事世界盃之旅 (BSOI4841)

【SHOI 2002】百事世界盃之旅 (BSOI4841)

【SHOI 2002】百事世界盃之旅
Description
……在2003年6月之前購買的百事任何飲料的瓶蓋上都會有一個百事球星的名字。只要湊齊所有百事球星的名字,就可以參加百事世界盃之旅的抽獎活動,獲取球星揹包、隨身聽,更可以赴日韓觀看世界盃。還不趕快行動!……”
你關上電視,心想:假設有n個不同球星的名字,每個名字出現的概率相同,平均需要買幾瓶飲料才能湊齊所有的名字呢?
Input
輸入一個數字n,2≤n≤33,表示不同球星名字的個數。                                                      
Output
輸出湊齊所有的名字平均需要購買的飲料瓶數。如果是一個整數則直接輸出。否則就用下面樣例中的格式分別輸出整數部分和小數部分。分數必須是不可約的。
Sample Input
5
Sample Output
11(5/12)
Hint

輸出說明:先輸出整數部分,若有小數部分,用括號把不可約分式括起來

思路:

分析 這是一道比較簡單的概率和期望問題。只要確定好計算方法,就可以很容易的得到公式。如果單獨考慮每一名球星,那麼就中了命題人的圈套。因為考慮單獨的一個球星的時候所買的“沒用”的飲料在考慮其他球星的時候可能會變成有用的。正確的思路是,假設現在已經有k個球星的名字,那麼要使球星的名字達到k+1個平均需要買多少瓶飲料?這是很容易計算的。 我們可以知道,第一個球星抽到的概率是1,第n個是1/n。那麼我們要從k個到k+1個球星的概率為(n-k)/n,所以期望為n/(n-k)。所以我們從沒有球星的名字開始,直到把所有的球星名字都湊齊,平均需要的飲料數(E)就可以計算出來:

ANS=n(1/1+1/2+1/3+....1/n)

由於題目的資料規模並不大,所以可以直接使用PASCAL的Comp或Int64(C/C++的long long)進行計算。而題目要求得到即約分數,只要在計算的時候使用分數並注意約分就可以了。

如果n很大,就要用公式 :   0.57721566490153286060651209 + ln(n)

(參與分數計算的都要開long long,整型一定會爆。。。)

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


#define pi acos(-1)
#define endl '\n'
#define srand() srand(time(0));
#define me(x,y) memset(x,y,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define close() ios::sync_with_stdio(0); cin.tie(0);
#define FOR(x,n,i) for(int i=x;i<=n;i++)
#define FOr(x,n,i) for(int i=x;i<n;i++)
#define W while
#define sgn(x) ((x) < 0 ? -1 : (x) > 0)
#define bug printf("***********\n");
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,1,-1,-1,1};
const int dy[]={0,1,0,-1,-1,1,-1,1};
const int maxn=1000;
const int maxx=1e7+100;
const double EPS=1e-7;
const int mod=998244353;
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
template<class T> void Scan(T &x)
{
    static int CH;
    while((CH=getchar())<'0'||CH>'9');
    for(x=CH-'0';(CH=getchar())>='0'&&CH<='9';x=(x<<3)+(x<<1)+(CH-'0'));
}




//freopen( "in.txt" , "r" , stdin );
//freopen( "data.out" , "w" , stdout );
//cerr << "run time is " << clock() << endl;




int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        LL a=1,b=1;
        for(LL i=2;i<=n;i++)
        {
            a=a*i+b;
            b*=i;
            LL r=__gcd(a,b);
            a/=r;b/=r;
        }
        a*=n;
        if(a%b==0)
            cout<<a/b<<endl;
        else
        {
            LL temp=__gcd(a,b);
            a/=temp;b/=temp;
            LL r=a/b;
            a=a-(b*r);
            cout<<r<<"("<<a<<"/"<<b<<")"<<endl;
        }
    }
}