http://www.tsinsen.com/A1295
试题来源
清华大学2011年百名信息学优秀高中学子夏令营
问题描述
有人打算送给你一条宝石项链,包含了N颗五颜六色(一共有M种颜色)的宝石。因为本问题中你只关心每个宝石的颜色,而且项链现在两头还没有接在一起,它可以被看成是一个数字串。
你希望在五颜六色的宝石中看到连续的一段同色宝石。因此,你定义一根宝石项链的幸运度是它最长的由同色宝石构成的连续子串的长度。 比如,项链112322211的幸运度是3,因为它包括了由同色宝石构成的子串222。而首尾的两个11并不构成连续1111,因为这个项链现在是串形的而不是环形的。
然而,你还没有见到这个项链。你只知道每个宝石是每种颜色的概率。并且,已知每个宝石的颜色分布是独立的。现在你希望在真的见到这条项链之前计算一下,这条项链的幸运度的期望是多少?
你希望在五颜六色的宝石中看到连续的一段同色宝石。因此,你定义一根宝石项链的幸运度是它最长的由同色宝石构成的连续子串的长度。 比如,项链112322211的幸运度是3,因为它包括了由同色宝石构成的子串222。而首尾的两个11并不构成连续1111,因为这个项链现在是串形的而不是环形的。
然而,你还没有见到这个项链。你只知道每个宝石是每种颜色的概率。并且,已知每个宝石的颜色分布是独立的。现在你希望在真的见到这条项链之前计算一下,这条项链的幸运度的期望是多少?
输入格式
输入的第一行有两个正整数N和M。
后面N行每行有M个非负实数。其中第i行第j列的数P_(i,j)含义是第i个宝石是颜色j的概率是P_(i,j)。每行的M个实数保证和为1。
后面N行每行有M个非负实数。其中第i行第j列的数P_(i,j)含义是第i个宝石是颜色j的概率是P_(i,j)。每行的M个实数保证和为1。
输出格式
一个实数,即这条项链的幸运度的期望。四舍五入至小数点后6位。
样例输入
4 2
1.0 0.0
0.5 0.5
0.0 1.0
0.5 0.5
1.0 0.0
0.5 0.5
0.0 1.0
0.5 0.5
样例输出
2.250000
样例说明
我们用1和2来分别表示两种颜色的宝石,则这串项链有四种等概率的情形:1121,1122,1221和1222。它们的幸运度分别是2,2,2,3,因此期望的幸运度是2.25。
数据规模和约定
30%的数据满足N≤16,M≤3。
60%的数据满足N≤100。
100%的数据满足2≤N≤1000,2≤M≤10。
p[i][j]为第i个为j的概率
用f[i][j][k]表示前i个,连续长度不超过j,最后一位是k的概率
用s[i][j]表示sigma(f[i][j][k])
用mul[i][j][k]表示i到j全部都是k的概率
显然有f[i][j][k]=s[i-1][j]*p[i][k]-(s[i-j-1][j]-f[i-j-1][j][[k])*mul[i-j][i][k]
显然答案为sigma((s[n][i]-s[n][i-1])*i)
#include <cstdio>
#include <iostream>
using namespace std;
int n,m,i,j,k;
double p[1001][11],ans;
double f[1001][1001][11],s[1001][1001],mul[1001][1001][11];
int main ()
{
cin >> n >> m;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
cin >> p[i][j];
for (k=1;k<=m;k++)
for (i=1;i<=n;i++)
{
mul[i][i][k]=p[i][k];
for (j=i+1;j<=n;j++)
mul[i][j][k]=mul[i][j-1][k]*p[j][k];
}
s[0][0]=1;
for (i=1;i<=n;i++) s[0][i]=1;
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
for (k=1;k<=m;k++)
{
f[i][j][k]=s[i-1][j]*p[i][k];
if (i-j-1>=0) f[i][j][k]-=(s[i-j-1][j]-f[i-j-1][j][k])*mul[i-j][i][k];
s[i][j]+=f[i][j][k];
}
}
for (i=1;i<=n;i++)
ans+=(s[n][i]-s[n][i-1])*i;
printf("%.6f",ans);
}