【NOI2006】 神奇口袋

题目描述
神奇口袋
【问题描述】
Pòlya 获得了一个奇妙的口袋,上面写着人类难以理解的符号。
Pòlya 看得入了迷,冥思苦想,发现了一个神奇的模型(被后人称为 Pòlya 模型)。为了生动
地讲授这个神奇的模型,他带着学生们做了一个虚拟游戏:
游戏开始时,袋中装入 a1 个颜色为 1 的球,a2 个颜色为 2 的球,...,at
个颜色为 t 的球,其中 ai ∈ Z + (1 ≤ i ≤ t ) 。
游戏开始后,每次严格进行如下的操作:
从袋中随机的抽出一个小球(袋中所有小球被抽中的概率相等),
Pòlya 独自观察这个小球的颜色后将其放回,
然后再把 d 个与其颜色相同的小球放到口袋中。
设 ci 表示第 i 次抽出的小球的颜色 (1 ≤ ci ≤ t ) ,
一个游戏过程将会产生一个颜色序列(c1,c2,...,cn,...)。
Pòlya 把游戏开始时 t 种颜色的小球每一种的个数 a1,a2,...,at 告诉了所有学
生。然后他问学生:一次游戏过程产生的颜色序列满足下列条件的概率有多大?
cx1 = y1 , cx2 = y2 ,L , cxi = yi ,L , cxn = yn
其 中 0<x1<x2<...<xn , 1≤yi≤t 。 换 句 话 说 , 已 知 (t , n , d , a1,a2,...,at ,
x1,y1,x2,y2,...,xn,yn) , 你 要 回 答 有 多 大 的 可 能 性 会 发 生 下 面 的 事 件 : “ 对 所 有k,1≤k≤n,第 xk 次抽出的球的颜色为 yk”。
【输入格式】
第一行有三个正整数 t,n,d;第二行有 t 个正整数 a1,a2,...,at,表示游戏开
始时口袋里 t 种颜色的球,每种球的个数。
以下 n 行,每行有两个正整数 xi,yi,表示第 xi 次抽出颜色为的 yi 球。
【输出格式】
要求用分数形式输出(显然此概率为有理数)。输出文件包含一行,格式为:
分子/分母。同时要求输出最简形式(分子分母互质)。特别的,概率为 0 应输出
0/1,概率为 1 应输出 1/1。
【样例】
样例 1 的输入 样例 1 的输出
          2 3 1 1/12
          1 1 
          1 1 
          2 2 
          3 1 
样例 2 的输入 样例 2 输出
          3 1 2 1/3
          1 1 1 
          5 1 
【样例 1 说明】
初始时,两种颜色球数分别为(1, 1),取出色号为 1 的球的概率为 1/2;第二
次取球之前,两种颜色球数分别为(2, 1),取出色号为 2 的球的概率为 1/3;第三
次取球之前,两种颜色球数分别为(2, 2),取出色号为 1 的球的概率为 1/2,所以
三次取球的总概率为 1/12。
【数据规模和约定】
1≤t,n≤1000,
1≤ak ,d≤10, 1≤x1<x2<...<xn≤10000,
1≤yk≤t
【评分方法】
本题没有部分分,你的程序的输出只有和我们的答案完全一致才能获得满
分,否则不得分。

 

题解

 

高精度乘法
 1 /*
 2     *Problem:    NOI2006 神奇口袋
 3     *Author :    Chen Yang
 4     *Time   :    2012.6.2 3:00 pm
 5     *State  :    Solved
 6     *Memo   :    数学证明、模拟、高精乘
 7 */
 8 #include <cstdio>
 9 #include <cstdlib>
10 #include <cstring>
11 using namespace std;
12 const int w = 10000, Max = 20000;
13 int t, n, d, Index, tot, text[Max], nem[Max], den[Max], a[1010];
14 bool notpri[Max];
15 struct big
16 {
17     int a[10000];
18     int &operator[](const int &_) {return a[_];}
19     big() {memset(a, 0, sizeof a), a[0] = a[1] = 1;}
20     big &operator *= (const int b)
21     {
22         for (int i=1; i<a[0]+1; ++i)
23             a[i] *= b;
24         for (int i=1; i<a[0]+1; ++i)
25             if (a[i] >= w) a[i+1] += a[i]/w, a[i] %= w;
26         while (a[a[0]+1]) ++a[0];
27         return *this;    
28     }
29     void write()
30     {
31         printf("%d", a[a[0]]);
32         for (int i=a[0]-1; i; --i) printf("%04d", a[i]);
33     }
34 } A, B;
35 
36 void maketext()
37 {
38     memset(notpri, 0, sizeof notpri); Index = 0;
39     for (int i=2; i<Max; ++i)
40     {
41         if (!notpri[i]) text[++Index] = i;
42         for (int j=1; j<Index+1 && i*text[j] < Max; ++j)
43         {
44             notpri[i*text[j]] = 1;
45             if (i % text[j] == 0) break;
46         }
47     }
48 }
49 
50 void updata(int x, int *a)
51 {
52     for (int i=1; i<Index+1; ++i)
53     if (text[i]>x) return; else
54     while (!(x%text[i])) ++a[i], x /= text[i];
55 }
56 
57 int main()
58 {
59     freopen("bag.in", "r", stdin);
60     freopen("bag.out", "w", stdout);
61     scanf("%d%d%d", &t, &n, &d);
62     for (int i=1; i<t+1; ++i) scanf("%d", a+i), tot += a[i]; 
63     maketext();
64     for (int i=1; i<n+1; ++i)
65     {
66         int x, y;
67         scanf("%d%d", &x, &y);
68         if (!a[y]) { printf("0/1"); exit(0); }
69         updata(a[y], nem);
70         updata(tot, den);
71         a[y] += d, tot += d; 
72     }
73     for (int i=1; i<Index+1; ++i) 
74     if (nem[i] && den[i])
75     {
76         if (nem[i]>den[i]) nem[i] -= den[i], den[i] = 0;
77         else den[i] -= nem[i], nem[i] = 0;
78     }
79     for (int i=1; i<Index+1; ++i)
80     {
81         while (nem[i]--) A *= text[i];
82         while (den[i]--) B *= text[i];
83     }
84     A.write(); printf("/"); B.write();
85     return 0;
86 }
posted @ 2012-06-03 07:35  datam  阅读(697)  评论(0编辑  收藏  举报