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;
}