2013寒假練習 1019 The Little Architect II

地址:http://acm.bit.edu.cn/mod/programming/view.php?id=670

用1*1*2的積木裝滿2*2*n的矩陣,一共有幾種方法。答案mod p輸出(1 <= n <= 1,000,000,000, 1 < p <= 1,000,000)

這題想了我好幾天,終於想明白每一層只有三種可能:不放向下的(情況0),放兩個相鄰的向下的(情況1),放四個向下的(情況2)。則由狀態壓縮DP的思想可以得到遞推公式:

dp[i][0]=dp[i-1][0]*2+dp[i-1][1]+dp[i-1][2];

dp[i][1]=dp[i-1][0]*4+dp[i-1][1];

dp[i][2]=dp[i-1][0];

初始條件

dp[0][0]=1,dp[0][1]=dp[0][2]=0;

這是由類似1022的思想想出來的。。然而n數據規模巨大,o(n)的遞推上去都不能被接受。。一開始想到的是因爲mod p,是否可以跑出循環節,結果仍舊超時,說明循環節都有可能很長。。

正解應該是矩陣快速冪優化遞推關係!

構造矩陣[2 4 1]  答案即變爲該矩陣的n次方的(0,0)位置的值!然後用矩陣快速冪瞬解。

                [1 1 0]

                [1 0 0]

好題。。

補充:劉果大神推出的另一個遞推公式:f(n)=3f(n-1)+3f(n-2)-f(n-3)

#include<iostream>
using namespace std;
typedef struct MATRIX
{
	__int64 a[3][3];
}matrix;
int n,p,i,j;
matrix operator * (matrix x,matrix y)
{
	matrix ans;
	for(i=0;i<=2;i++)
	{
		for(j=0;j<=2;j++)
		{
			ans.a[i][j]=(x.a[i][0]*y.a[0][j]%p+x.a[i][1]*y.a[1][j]%p+x.a[i][2]*y.a[2][j]%p)%p;
		}
	}
	return ans;
}
int main()
{
	while(~scanf("%d%d",&n,&p))
	{
		matrix I={2,4,1,1,1,0,1,0,0};
		matrix t={1,0,0,0,1,0,1,0,0};
		while(n>1)
		{	
			if(n%2) t=t*I;
			n/=2,I=I*I;	
		}
		t=t*I;
		printf("%d\n",t.a[0][0]);
	}
	return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章