Tsinsen1295 necklace

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


你可能感兴趣的:(Tsinsen1295 necklace)