POJ 3150 Cellular Automaton 矩阵dp

http://poj.org/problem?id=3150

思路:利用矩阵A,B具有A[i][j]=A[i-1][j-1],B[i][j]=B[i-1][j-1](i-1<0则表示i-1+n,j-1<0则表示j-1+n)
我们可以得出矩阵C=A*B也具有这个性质
C[i][j]=sum(A[i][t]*B[t][j])=sum(A[i-1][t-1],B[t-1][j-1])=sum(A[i-1][t],B[t][j-1])=C[i-1][j-1]
也就是说我们知道了矩阵C的某一行,就可以知道所有行,所以我们对每个矩阵保存其第一行即可
矩阵的每一个元素也可得知C[i][j]=C[0][j-i] (j-i<0时j-i表示j-i+n)
这样每次我们求C=A*B只要求c[j]=C[0][j]=sum(A[0][t]*B[t][j])=sum(a[t]*b[t-j]).
只求一行这样复杂度就降下来了。

代码:

#include<stdio.h>
#include<string.h>
__int64 N ,M ,D ,K ;
__int64 start[510] ;
__int64 m[510] ;
__int64 c[510] ;
__int64 res[510] ;

void cal(__int64 A[] , __int64 B[]){
	for(int i=0;i<N;i++){
		c[i] = 0 ;
		for(int t=0;t<N;t++){
			c[i] += A[t]*B[(N-t+i)%N] ;	
		}
	}
	for(int i=0;i<N;i++)
		A[i] = c[i]%M ;	
}
void solve(){
	while(K){
		if(K&1)	cal(res , m);
		cal(m,m);
		K >>= 1;	
	}
	for(int i=0;i<N;i++){
		c[i] = 0 ;
		for(int t=0;t<N;t++){
			c[i] += res[(N+t-i)%N]*start[t] ;	
		}	
		c[i] %= M ;
	}
}
int main(){
	while(scanf("%I64d%I64d%I64d%I64d",&N,&M,&D,&K) == 4){
		for(int i=0;i<N;i++)
			scanf("%I64d",&start[i]);	
		memset(res, 0, sizeof(res));
		memset(m , 0 ,sizeof(m));
		m[0] = 1 ; res[0] = 1 ;
		for(int i=1;i<=D;i++){
			m[i] = m[N-i] = 1 ;	
		}		
		solve();
		for(int i=0;i<N;i++){
			printf("%I64d%c",c[i],i==N-1?'\n':' ');
		}
	}		
	return 0 ;	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值