【矩阵快速幂+递推方程】The Little Architect

24.The Little Architect

成绩: 10 / 折扣: 0.8

Description

Silence is a little architect, he likes to make all kinds of buildings with his building blocks. Now he has a new problem. He want to build a building of size 2 * 2 * n. But he only has one kind of block of size 1 * 1 * 2. Now he wants to know how many ways he can build the building.

Input

There are several lines in the input. Each line is a set of input data. There are two integers n and p (1 <= n <= 1,000,000,000, 1 < p <= 1,000,000) in each test case. The input is end with EOF.

Output

For each test case, output a single line contains one integer which is the number of differentways he can build the building. Because of the answer may be very large, you just need to output the answer mod p.

Sample in

1 999997
2 999997
6 999997

Sample out

2
9
1681

思路分析与讲解:

大家应该已经知道这题的做法了
矩阵快速幂+状态方程
显然,矩阵快速幂不是难点,这个不会的稍微查一下资料就能知道了,那么我们的难点就在于如何推导出状态方程

一开始我是毫无思路的瞎推倒,但是了解了状态压缩DP这个东西之后,我很顺利的推出了公式,而且是巨简单的公式,包学包会!


我们已经知道,入手是从第N层的状态开始。
于是可以得到六种情况
0 0         0 0        1 1         1 0           0 1          1 1
0 0         1 1        0 0         1 0           0 1          1 1
第一情况,也就是说注定了倒数第二层也是竖放的,于是这种情况的总数为f(n-2)
第六种情况,我们可以知道,第一层是满放的,于是总数为2*f(n-1)
中间四种情况可以一起考虑,于是直接给它一个状态,我们设为G,于是
我们现在就有公式
f(n) = 2*f(n-1)+f(n-2)+4*G(n-1)---------------1式
对于这个公式,我们发现现在我们只要找到G状态的递推方程即可


于是,研究一下G状态,会知道,倒数第二层的状态为
0 0          0 1
0 0          0 1
两种情况
对于第一种情况,直接用回之前的经验,有f(n-2)种
对于第二种情况,也是之前的经验,有G(n-2)种
于是乎,我们又得到了一个很重要的状态方程,G(n-1)=f(n-2)+G(n-2)---------------------2式


联立1,2两式,我们可以轻易的得到最后的方程


f(n) = 3*f(n-1) + 3*f(n-2) - f(n-3)


至此,此题也就迎刃而解~




最后再贴一下本人的AC代码吧,仅供参考:


#include <stdio.h>
#include <string.h>

typedef struct
{
	long long num[3][3] ;
}node;

long long p ;

node fun(node a , node b )
{
	int i , j , k ;
	node c ;
	memset(c.num,0,sizeof(c.num)) ;
	for( i = 0 ; i < 3 ; i++ ) {
		for( j = 0 ; j < 3 ; j++ ) {
			for( k = 0 ; k < 3 ; k++ )
				c.num[i][j]+=a.num[i][k]*b.num[k][j] ;
			c.num[i][j]%=p ;
		}
	}
	return c ;
}

int main()
{
	long long n , b[3] = { 2 , 9 , 32 } ;
	node a , t ;
	while( ~scanf("%lld%lld",&n,&p) ) {
		memset(a.num,0,sizeof(a.num)) ;
		a.num[0][0] = 3 ;
		a.num[1][0] = 3 ;
		a.num[2][0] = -1 ;
		a.num[0][1] = 1 ;
		a.num[1][2] = 1 ;
		memset(t.num,0,sizeof(t.num)) ;
		t.num[0][0] = 1 ;
		t.num[1][1] = 1 ;
		t.num[2][2] = 1 ;
		if(n>3) {
			n = n-3 ;
			while(n>=1) {
				if(n%2==1)
					t = fun(t,a);
				n = n/2 ;
				a = fun(a,a);
			}
			long long temp = (b[2]*t.num[0][0]+b[1]*t.num[1][0]+b[0]*t.num[2][0])%p ;
			if( temp < 0 ) temp+=p ;
			printf("%lld\n",temp) ;
		}
		else printf("%lld\n",b[n-1]%p) ;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值