1. 程式人生 > >湖南省第六屆大學生程式競賽--戰場的數目

湖南省第六屆大學生程式競賽--戰場的數目

題目I

戰場的數目

在上題中,假設戰場的圖形周長為p,一共有多少種可能的戰場?

例如,p<8時沒有符合要求的戰場,p=8時有2種戰場:

p=109種戰場:

要求輸出方案總數模987654321的值。

輸入

輸入檔案最多包含25組測試資料,每個資料僅包含一行,有一個整數p1<=p<=109),表示戰場的圖形周長。p=0表示輸入結束,你的程式不應當處理這一行。

輸出

對於每組資料,輸出僅一行,即滿足條件的戰場總數除以987654321的餘數。

樣例輸入

樣例輸出

7

8

9

10

0

0

2

0

9

==============================================

這道題開始想著構建一個二維陣列,然後列舉。。不過2s後急忙否定了這個答案,因為周長《=1000000000

後來想那就遞迴,先找出一種情況,例如p=8時候戰場的形狀,再來遞迴下一種情況,也就是p=10的情況(加上一些方塊,使得周長+2,就看加上方塊的種類個數  也就變成了 f(10) = f(8) + h(8)  h(8)代表可以加上幾種方塊。)  後來水平有限,也覺得稍稍複雜,就沒繼續想此方法,希望有高手能指教。

後來經群裡一大神提醒,立馬明白了這道題。

在說這道題之前,要說一下這道題目的限制條件。在上一題中,題目限制戰場不能為矩形,並且要考慮重力。也就是說不能堆出一些奇奇怪怪的戰場。

好,開始分析題目吧

==============================================

此題其實暗含規律,找到規律即可輕鬆解決。

規律如下:

先考慮矩形情況,也就是P=4時,有1種,P=6時,有2種

1.若戰場最左邊有高度為1的方塊,那麼若將此方塊減掉,則P-2。

2.若戰場最右邊有高度為1的方塊,那麼若將此方塊減掉,則P-2。

3.若戰場的最下層去掉,那麼P-2; (只減少左右兩邊的周長)

4.若戰場的左邊和右邊皆有高度為1的方塊,由於1.2情況包含此情況,因此要減去此情況。此時P-4.

那麼,得到的規律即為:f(p) = 3*f(p - 2) - f(p - 4) (p>4)

基於此規律  即可得到遞推公式 思路也就明確了。

在此使用矩陣快速冪,若不清楚,請參考:http://www.cnblogs.com/dongsheng/archive/2013/06/02/3114073.html

在此附上程式碼:

#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod=987654321;

ll A[2][2],B[2][2],T[2][2];

void pow(int n)
{
	if(n==0)
	{
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
				B[i][j]=(i==j);
        
		return;
	}
	if(n&1)
	{
		pow(n-1);
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
			{
				T[i][j]=0;
					for(int k=0;k<2;k++)
						T[i][j]=(T[i][j]+A[i][k]*B[k][j])%mod;
			}
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
			{
				B[i][j]=T[i][j];
			}
		
	}
	else
	{
		pow(n/2);
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
			{
				T[i][j]=0;
					for(int k=0;k<2;k++)
						T[i][j]=(T[i][j]+B[i][k]*B[k][j])%mod;
			}
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
			{
				B[i][j]=T[i][j];
			}
		
	}
}

int main()
{
  int n;
  A[0][0]=1;	A[0][1]=1;
  A[1][0]=1;	A[1][1]=0;
  while (scanf("%d", &n) == 1 && n)
  {
	ll ans=0;
	if(n&1) ans=0;
	else if(n<4) ans=0;
	else
	{
		pow(n-4);
		ans=B[0][0]-n/2+1;
		ans%=mod;
		if(ans<0)ans+=mod;
	}
	printf("%lld\n",ans);
  }

  return 0;
}