关闭

【bzoj2510】弱题 概率dp+循环矩阵矩阵乘法

666人阅读 评论(0) 收藏 举报
分类:

  真心觉得是道不错的题,非常简单的dp方程,然后O(n^3)的矩阵乘法都是非常裸的,结果发现最后n<=1000的点是过不去的,想了一会决定看一下hzwer的题解,然后就学了一下循环矩阵,真心是个不错的东西,第一次见是在SDOI2015的时候,确实是个神奇的东西。

  本题的矩阵是一个循环矩阵,每一行都是由前一行右移一位得到的,于是就有一个非常好的性质,我们只需要保存第一行的情况,然后算出答案后,依次右移即可,具体计算方式如下。

f[i]=f[i-1]/M+f[i]*(1-1/M)


(f[1] f[2] ^ f[n])*(1-1/M 1/M   ^ 0    )=(f[1] f[2] …… f[n])
                      (0  1-1/M ……  0 )
                       (………………………)
     (0  0  ……  1/M )
                             (1/M  0 ……  1-1/M)


res[1]=a[1][1]*a[1][1]+a[1][2]*a[1][n]+……+a[1][n]*a[1][2]
=res[1]*res[1]+res[2]*res[n]+res[3]*res[n-1]+……+res[n]*res[2]


res[2]=a[1][1]*a[1][2]+a[1][2]*a[2][2]+……+a[1][n]*a[n][2]
=a[1][1]*a[1][2]+a[1][2]*a[1][1]+a[1][3]*a[1][n]+……+a[1][n]*a[1][3]

=res[1]*res[2]+res[2]*res[1]+res[3]*res[n]+……+res[n]*res[3]


res[3]=a[1][1]*a[1][3]+a[1][2]*a[2][3]+……+a[1][n]*a[n][3]
=a[1][1]*a[1][3]+a[1][2]*a[1][2]+……+a[1][n]*a[1][4]
=res[1]*res[3]+res[2]*res[2]+res[3]*res[1]+……+res[n]*res[4]

res[(i+j-2)mod n+1]+=res[i]*res[j]

ans[1]=f[1]*res[1]+f[2]*res[n]+f[3]*res[n-1]+……+f[n]*res[2]
ans[2]=f[1]*res[2]+f[2]*res[1]+f[3]*res[n]+……+f[n]*res[3]
ans[3]=f[1]*res[3]+f[2]*res[2]+f[3]*res[1]+……+f[n]*res[4]
ans[n]=f[1]*res[n]+f[2]*res[n-1]+f[3]*res[n-2]+……+f[n]*res[1]

ans[(i+j-2)mod n+1]+=f[i]*res[j]

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

※   res[(i+j-2)mod n+1]+=res[i]*res[j]
※   ans[(i+j-2)mod n+1]+=f[i]*res[j]


也是比较神的一种计算方式,真心跪烂了。。。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 1010

using namespace std;

int n,m,k;
int a[maxn];
double b[maxn];

struct matrix
{
	double a[maxn];
	matrix operator*(matrix b)
	{
		matrix ans;
		memset(ans.a,0,sizeof(ans.a));
		for (int i=1;i<=n;i++) 
		  for (int j=1;j<=n;j++)
		    ans.a[(i+j-2)%n+1]+=a[i]*b.a[j];
		return ans;
	}
}ans,res;

int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	res.a[1]=1.0-1.0/m;res.a[2]=1.0/m;
	ans.a[1]=1.0;
	while (k)
	{
		if (k&1) ans=ans*res;
		res=res*res;
		k/=2;
	}
	for (int i=1;i<=n;i++)
	  for (int j=1;j<=n;j++)
	    b[(i+j-2)%n+1]+=a[i]*ans.a[j];
	for (int i=1;i<=n;i++) printf("%.3lf\n",b[i]);
	return 0;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:154624次
    • 积分:4505
    • 等级:
    • 排名:第6944名
    • 原创:302篇
    • 转载:0篇
    • 译文:0篇
    • 评论:70条
    最新评论