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; }