f(i, j, k)表示到第i位,最大长度为j,当前位为k的概率。
那么,我们要使用O(1)的时间完成转移,很容易想到部分和优化。
转移分为两种情况。
第一种,最后一段长度=历史最大长度,那么f(i, j, k)要加上sigma{f(i - j, p, q) * probability(i - j + 1, i, k)}(1 <= p <= j, 1 <= q <= M && q != k),显然是可以部分和的。
第二种,最后一段长度 < 历史最大长度,那么f(i, j, k)要加上sigma{f(i - p, j, q) * probability(i - p + 1, i, k)}(1 <= p < j,1 <= q <= M && q != k),显然也是可以部分和的,取出一段和的时候可以使用类似取出一段hash的计算方法。
其中probability(i, j, k)表示从第i位到第j位全都为k的概率,是可以在O(N^2M)的时间内预处理出来的。
整体时间复杂度O(N^2M)。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define N 1001
#define M 11
using namespace std;
int n,m;
double ans,p[N][M],sum[N][N],f[N][N][M],g[N][N][M],h[N][N][M],u[M][N][N];
int main()
{
scanf("%d%d",&n,&m);
F(i,1,n) F(j,1,m) scanf("%lf",&p[i][j]);
F(k,1,m) F(i,1,n)
{
u[k][i][i]=p[i][k];
F(j,i+1,n) u[k][i][j]=u[k][i][j-1]*p[j][k];
}
f[0][1][0]=1;
F(i,0,n) F(j,1,m) h[0][i][j]=1;
F(i,1,n) F(j,1,n)
{
if (i>=j) F(k,1,m)
{
f[i][j][k]+=h[i-j][j][k]*u[k][i-j+1][i];
if (j>1) f[i][j][k]+=(g[i-1][j][k]-g[i-j][j][k]*u[k][i-j+1][i-1])*p[i][k];
sum[i][j]+=f[i][j][k];
}
F(k,1,m)
{
g[i][j][k]=g[i-1][j][k]*p[i][k]+sum[i][j]-f[i][j][k];
h[i][j][k]=h[i][j-1][k]+sum[i][j]-f[i][j][k];
}
}
F(i,1,n) F(j,1,m) ans+=f[n][i][j]*i;
printf("%.6lf\n",ans);
return 0;
}
原文:http://blog.csdn.net/aarongzk/article/details/51138661