[BZOJ2510] 弱题 [矩阵乘+循环矩阵优化]

式子是最基本的,通过式子:

$f[i][j]=(1/m)*f[i-1][j-1]+(1-1/m)*f[i-1][j] (1<j<=n)$

$f[i][1]=(1/m)*f[i-1][n]+(1-1/m)*f[i-1][1] $

对于这个式子我是这么理解的,首先把它拆开:

$f[i][j]=f[i-1][j]+(1/m)*f[i-1][j-1]-(1/m)*f[i-1][j] $

也就是说上一轮期望值+选中j-1的概率×期望1-选中j的概率×期望1

矩阵快速幂?$ O(n^3log2(k))$ 瞬间爆炸

可以从上表中发现规律:这是一个循环矩阵!

所以我们可以通过循环矩阵的式子:

f[x]=sigma  a[i]*b[j] ((i+j-2)%n+1==x)

于是就 $ O(n^2log2(k))$ 解决了


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define r register 
using namespace std;
int n,m,k;
struct Ma{double f[1050];}A,B;
Ma X(Ma x,Ma y)
{
		Ma ans;
		memset(ans.f,0,sizeof(ans.f));
		for(r int j=1;j<=n;j++)
		{
				for(r int k=1;k<=n;k++)
				{
						ans.f[(j+k-2)%n+1]+=x.f[j]*y.f[k];
				}
		}
		return ans;
}
Ma poww(Ma x,int y)
{
		Ma ans;
		memset(ans.f,0,sizeof(ans.f));
		ans.f[1]=1;
		while(y)
		{
				if(y&1) ans=X(x,ans);
				y>>=1;
				x=X(x,x);
		}
		return ans;
}
int main()
{
		//freopen("1.in","r",stdin);
		//freopen("1.out","w",stdout);
		scanf("%d%d%d",&n,&m,&k);
		if(m==0)
		{
				for(int i=1;i<=n;i++) puts("0.000");
				return 0;
		}
		memset(B.f,0,sizeof(B.f));
		for(int i=1,x;i<=n;i++) 
		{
				scanf("%d",&x);
				A.f[i]=(double)x;
		}
		B.f[1]=(double)(m-1)/(double)m;
		B.f[2]=(double)1/(double)m;
		A=X(A,poww(B,k));
		for(int i=1;i<=n;i++)
		{
				printf("%0.3lf\n",A.f[i]);
		}
		return 0;
}
 

 

posted @ 2019-07-18 20:58  ATHOSD  阅读(401)  评论(0编辑  收藏  举报