Input
第一行有三个正整数t,n,d;第二行有t个正整数a1,a2,…,at,表示游戏开始时口袋里t种颜色的球,每种球的个数。以下n行,每行有两个正整数xi,yi,表示第xi次抽出颜色为的yi球。
Output
要求用分数形式输出(显然此概率为有理数)。输出文件包含一行,格式为:分子/分母。同时要求输出最简形式(分子分母互质)。特别的,概率为0应输出0/1,概率为1应输出1/1。
Sample Input 1
2 3 1
1 1
1 1
2 2
3 1
Sample Output 1
1/12
Sample Input 2
3 1 2
1 1 1
5 1
Sample Output 2
1/3
这道题目看起来似乎无从下手,但仔细观察则可以发现其中可以作等效处理。先看一个证明:
有了以上结论,就可以将每次的概率直接累乘(至于约分,可以筛出20000以内的素数表,然后保存分子分母的各个因数)。当然,用高精度是显然的。代码:
/****************************\
* @prob: NOI2006 bag *
* @auth: Wang Junji *
* @stat: Accepted. *
* @date: June. 2nd, 2012 *
* @memo: 模拟、高精度乘法 *
\****************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
const int maxN = 20010, BIT = 10000;
bool tag[maxN];
int p[maxN], cnt_num[maxN], cnt_den[maxN], ball[maxN], top, T, n, D;
class Huge
{
private: int len, ele[maxN];
public:
Huge(int x) {for (len = 0; x; x /= BIT) ele[len++] = x % BIT;}
Huge(): len(1) {memset(ele, 0, sizeof ele);}
Huge &operator*=(const int &x)
{
for (int i = 0; i < len; ++i) ele[i] *= x;
for (int i = 0; i < len; ++i) ele[i + 1] += ele[i] / BIT, ele[i] %= BIT;
while (ele[len]) ++len; return *this;
}
void print()
{
printf("%d", ele[len - 1]);
for (int i = len - 2; i > -1; --i) printf("%04d", ele[i]);
return;
}
} num(1), den(1);
inline void update(int *cnt, int x)
{
for (int i = 0; x && i < top; ++i)
for (; x % p[i] == 0; x /= p[i]) ++cnt[i];
return;
}
inline void mkprime()
{
for (int i = 2; i < maxN; ++i)
if (!tag[i]) p[top++] = i;
else for (int j = 0; j < top && p[j] * i < maxN; ++j)
{tag[i * p[j]] = 1; if (i % p[j] == 0) break;}
return;
}
int main()
{
freopen("bag.in", "r", stdin);
freopen("bag.out", "w", stdout);
scanf("%d%d%d", &T, &n, &D); int sum = 0; mkprime();
for (int i = 0; i < T; ++i) scanf("%d", ball + i), sum += ball[i];
for (int i = 0; i < n; ++i)
{
int x, y; scanf("%d%d", &x, &y); --y;
if (!ball[y]) {printf("0/1\n"); return 0;}
update(cnt_num, ball[y]), ball[y] += D;
update(cnt_den, sum), sum += D;
}
for (int i = 0, tmp; i < top; ++i)
{
tmp = std::min(cnt_num[i], cnt_den[i]);
cnt_num[i] -= tmp, cnt_den[i] -= tmp;
while (cnt_num[i]--) num *= p[i];
while (cnt_den[i]--) den *= p[i];
}
num.print(); printf("/"); den.print(); return 0;
}