ch_g

ECUST_ACMer —— ch_g
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[EOJ][397][Typing monkey][字符串+概率+母函数]

Posted on 2011-05-04 12:42  ch_g  阅读(1032)  评论(0编辑  收藏  举报
/*
题目:Typing monkey
题目来源:EOJ 397
题目难度:中等偏难
题目内容:
有一只猴子敲键盘(只敲26个字母,小写),26个字母敲到的概率分别给出,再给两个长度不超过16的字符串,
求第一个字符串比第二个字符串先出现的概率
解题思路:
字符串 + 概率 + 母函数(《具体数学》(英文版.第2版)第八章概率母函数的p410)

下面是我看了《具体数学》8.4章节后的理解:(可能有些地方说的不清楚,建议先看《具体数学》8.4)
为了方便理解我们把问题简化,只考虑两个字符(26个字符的情况是类似的)。假定这两个字符分别为‘H’和‘T’。
其中‘H’出现的概率为p;‘T’出现的概率为q。
则字符串THTTH出现的概率为

Pr(THTHH) = qpqpp = p^3 * q^2 --------------------------------------------(《具体数学》P403 )

下面先引入字符串集合无限和的定义:
我们考虑由所有以“HH”终止且最后位置之前没有出现连续H的字符串集合为

Ω = {HH, THH, TTHH, HTHH, TTTHH, THTHH, HTTHH, ...}; -----------------(《具体数学》P403 )

现在定义字符串集合Ω所有元素的无限和为

S = HH + THH + TTHH + HTHH + TTTHH + THTHH + HTTHH + ... -----------------(《具体数学》P403 )

如果我们用px替换每个H,用qx替换每个T,则我们可以得到一个概率母函数,而这个概率母函数正是“直至出现
两个连续H时终止敲击键盘”这个事件的概率母函数

考虑如果题目所求的两个字符串分别为 A=“HHT”, B=“HTT”时
令A先于B出现的字符串无限和为Sa,B先于A的字符串无限和为Sb, A、B都未出现过的字符串无限和为N,则有

Sa = HHT + HHHT + THHT + HHHHT + HTHHT + THHHT + ...;
Sb = HTT + THTT + HTHTT + TTHTT + THTHTT + TTTHTT + ...;
N = 1 + H + T + HH + HT + TH + TT + HHH + HTH + THH + ... ---------------(《具体数学》P409 )

然后我们可以很容易的得到下面的方程组 --------------------------------------------(《具体数学》P409 )
1 + N(H + T) = N + Sa + Sb;
N HHT = Sa;
N HTT = Sa T + Sb;

事实上,我们可以总结得到更一般的方程组 -------------------------------------------(《具体数学》P409 )
1 + N(H + T) = N + Sa + Sb;
l min(l,m)
NA = Sa Σ A(l-k)[A(k) = A{k}] + Sb Σ A(l-k)[B(k) = A{k}]; ---------------- (1)
k=1 k=1
min(l,m) m
NB = Sa Σ B(m-k)[A(k) = B{k}] + Sb Σ B(m-k)[B(k) = B{k}]; ---------------- (2)
k=1 k=1

其中l为A的长度,m为B的长度。A(k)表示A最后k个字符,A{k}表示A的前k个字符 ----------------(《具体数学》P407 )
比如:若A=THTTH,则有
A(1) = H, A(2) = TH, A(3) = TTH, A(4) = HTTH
A{1} = T, A{2} = TH, A{3} = THT, A{4} = THTT
而[x=y]中等式x=y成立时,[x=y] = 1,否则[x=y] = 0;

例如: A = HTTHTHTH, B = THTHTTH 时有 ----------------------------(《具体数学》P410 )
N HTTHTHTH = Sa TTHTHTH + Sa + Sb TTHTHTH + Sb THTH;
N THTHTTH = Sa THTTH + Sa TTH + Sb THTTH + Sb.

min(l,m)
我们令 A:B = Σ Pr(B(m-k)) / Pr(B) [A(k) = B{k}]
k=1
min(l,m)
= Σ 1/Pr(B{k}) [A(k) = B{k}] -------------------(求解本题的关键公式)
k=1

则(1)式和(2)式消去N可以简化为

Sa(A:A) + Sb(B:A) = Sa(A:B) + Sb(B:B); --------------------------(《具体数学》P410 )

进而有
Sa B:B - B:A
—— = ————————— ------------------------------------------------(《具体数学》P410 )
Sb A:A - A:B

这个比例就是A先出现的情况总数和B先出现的情况总数之比

则A先出现的概率为 (B:B - B:A) / (B:B - B:A + A:A - A:B)
B先出现的概率为 (A:A - A:B) / (B:B - B:A + A:A - A:B)
(当然,上面讨论的情况要求满足:A不能为B的子串,B也不能为A的子串)
做题日期:2011.5.3
*/
#include
<cstdio>
#include
<iostream>
#include
<cstring>
#include
<string>
#include
<ctime>
#include
<cstdlib>
using namespace std;

const int T = 26;
double p[T];
char a[T], b[T];

double calc(char *a, char *b) {
int la = strlen(a);
int lb = strlen(b);
int len = min(la, lb);
double ans = 0, r = 1;
for (int i = 1; i <= len; ++i) {
r
/= p[b[i - 1] - 'a'];
if (strncmp(a + la - i, b, i) == 0) ans += r;
}
return ans;
}

void solve() {
for (int i = 0; i < T; ++i)
scanf(
"%lf", p + i);
scanf(
"%s%s", a, b);
int la = strlen(a);
int lb = strlen(b);
int t = min(la, lb);
for (int i = 0; i < lb - la; ++i) {
if (strncmp(b + i, a, la) == 0) {
printf(
"%.8lf\n", 1.0);
return;
}
}
for (int i = 0; i < la - lb; ++i) {
if (strncmp(a + i, b, lb) == 0) {
printf(
"%.8lf\n", 0.0);
return;
}
}
if (strncmp(a + la - t, b + lb - t, t) == 0) {
printf(
"%.8lf\n", 0.0);
return;
}
double u = calc(b, b) - calc(b, a);
double v = calc(a, a) - calc(a, b);
printf(
"%.8lf\n", u / (u + v));
}

int main() {
#ifndef ONLINE_JUDGE
freopen(
"test", "r", stdin);
#endif
int cas;
scanf(
"%d", &cas);
while (cas--) {
solve();
}
return 0;
}