【NOI2006】 神奇口袋
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
神奇口袋 【问题描述】 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 【评分方法】 本题没有部分分,你的程序的输出只有和我们的答案完全一致才能获得满 分,否则不得分。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }