1. 程式人生 > >動態規劃——有趣的數(ccf)

動態規劃——有趣的數(ccf)

題目描述:

我們把一個數稱為有趣的,當且僅當:
1. 它的數字只包含0, 1, 2, 3,且這四個數字都出現過至少一次。
2. 所有的0都出現在所有的1之前,而所有的2都出現在所有的3之前。
3. 最高位數字不為0。
因此,符合我們定義的最小的有趣的數是2013。除此以外,4位的有趣的數還有兩個:2031和2301。
請計算恰好有n位的有趣的數的個數。由於答案可能非常大,只需要輸出答案除以1000000007的餘數。

解題思路:ccf的測試資料恐怖到極致,以至於我見了這道題根本沒有任何暴力的想法,我知道n位數與n-1位數絕對存在著某種關係~果然!

我們假設dp[i][j]表示填到第i位數時處於第j個狀態。 
那麼共有六種合法狀態,括號表示重複出現的數字   
0--01(2)3
1--(0)1(2)3
2--01(2)(3)
3--(0)(1)(2)3
4--(0)1(2)(3)
5--(0)(1)(2)(3)

那麼這個問題就很明顯了,任何n一種狀態,都是由滿足條件的幾個n-1狀態組成的

哦對了,注意每次都要取餘~

#include<stdio.h>
/*
dp[i][j]表示填到第i位數時處於第j個狀態。 

共有六種合法狀態,括號表示重複出現的數字   

0--01(2)3
1--(0)1(2)3
2--01(2)(3)
3--(0)(1)(2)3
4--(0)1(2)(3)
5--(0)(1)(2)(3)

*/ 

int main()
{
	int i,n;
	__int64 dp[1010][10];
	while(scanf("%d",&n)!=EOF)
	{
for (i=1;i<=n;i++)
{
 dp[i][0]=1;
 dp[i][1]=(dp[i-1][1]*2+dp[i-1][0])%1000000007;
 dp[i][2]=(dp[i-1][2]+dp[i-1][0])%1000000007;
 dp[i][3]=(dp[i-1][3]*2+dp[i-1][1])%1000000007;
 dp[i][4]=(dp[i-1][4]*2+dp[i-1][2]+dp[i-1][1])%1000000007;
 dp[i][5]=(dp[i-1][5]*2+dp[i-1][4]+dp[i-1][3])%1000000007;
 }
 printf("%I64d\n",dp[n][5]);
}
return 0;
}