1. 程式人生 > >ccf有趣的數

ccf有趣的數

201312-4
試題名稱: 有趣的數
時間限制: 1.0s
記憶體限制: 256.0MB
問題描述:

問題描述

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

輸入格式

  輸入只有一行,包括恰好一個正整數n (4 ≤ n ≤ 1000)。

輸出格式

  輸出只有一行,包括恰好n 位的整數中有趣的數的個數除以1000000007的餘數。

樣例輸入

4

樣例輸出

3

這道題用了dp的思想,感覺就是把當前的所有可能的狀態列出來,然後當前的狀態又由之前的子狀態得出來.

用陣列dp[i][j],第i表示第i位數,j表示當前的狀態

其實這道題只有六種狀態:

1>  0,1,(2) 3

2> (0),1,(2),3

3> 0,1,(2),(3)

4> (0),(1),(2),3

5> (0),1,(2),(3)

6>(0),(1),(2),(3)

挑幾個狀態來解釋,括號中的數表示之前已經存在的數,比如說2就一定是首位,那麼它就在六種狀態中都要括號,如果dp[3][4]來舉例,那麼說明dp[3][4]補充了第三位數之後,還要保持第4種狀態的意思,

那麼,之前有什麼情況使得第三位數加上去了,還是隻有0,1,2呢,

顯然上一步時是第二種狀態,那麼第三位數只能是1,也就是一種情況,或者上一步時就是第四種情況,那麼第三位數只能是1或者2,因為之前已經有1了,那就不能讓0在1後面.所以

dp[3][4] = (dp[2][2] + dp[2][4]*2%1000000007)%1000000007種狀態,當然這個例子舉得不好,第三位數之前怎麼可能就已經有0,1,2了,大概就是瞎舉例子,求輕噴....

然後取模要注意,因為乘了2後有可能會超出資料範圍,所以也要mod,

數值型別都取long long,因為太大了.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <string.h>
#define mor 1000000007

using namespace std;
LL dp[1005][6];


int main(int argc, char** argv) {
	long long n;
	cin>>n;
	memset(dp,0,sizeof(dp));
	dp[1][0] = 1;
	for(long long i = 2;i<=n;i++)
	{
		dp[i][0] = 1;
		dp[i][1] = (dp[i-1][0]+2*dp[i-1][1]%mor)%mor;
		dp[i][2] = (dp[i-1][0]+dp[i-1][2])%mor;
		dp[i][3] = (dp[i-1][1]+(dp[i-1][3]*2)%mor)%mor;
		dp[i][4] = (dp[i-1][1]+dp[i-1][2]+(dp[i-1][4]*2)%mor)%mor;
		dp[i][5] = (dp[i-1][3]+dp[i-1][4]+(dp[i-1][5]*2)%mor)%mor;
	}
	cout<<dp[n][5];
	return 0;
}