問題描述
我們把一個數稱為有趣的,當且僅當:
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
網上看到的思路,采用動態規划思想,每一次決策都基於前一次決策的最優解。
即對一個n位數的解都基於前一個n-1位的數的最優解。
我們對一個數的第n位規定一個狀態集:即到這一位為止還有幾個數字沒有使用(我們有0123共四個數)。
根據規則來說,共有6種狀態:
0--用了2,剩0,1,3 1--用了0,2,剩1,3 2--用了2,3,剩0,1 3--用了0,1,2,剩3 4--用了0,2,3,剩1 5--全部用了
於是我們需要讓用戶輸入位數,然后聲明同等位數的數組,在每個元素里是6種狀態中所包含的該狀態下的“符合條件的數”的個數。(是二維數組)
然后用動態規划思想從最小位數開始逐層往上計算。
例:
對於i位狀態5的計算,考慮在i-1位時有三種狀態可以到達狀態5,第3種,此時只能在i位填3,所以*1;第4種,此時只能在i位填1,所以*1;第5種,此時能在i位填2或3(參考規則),所以*2;
states[i][5] = (states[j][3] + states[j][4] + states[j][5] * 2) % mod;
其他同上。
由於采用動態規划,所以取余並沒有什么影響。
最后完成計算只需輸出i位的第5種狀態中的個數。
1 1 #include <iostream> 2 2 3 3 using namespace std; 4 4 5 5 int main(){ 6 6 long long mod = 1000000007; 7 7 long long n; 8 8 cin>>n; 9 9 long long **states = new long long*[n+1]; 10 10 for(long long i =0;i<n+1;i++) 11 11 states[i]=new long long[6]; 12 12 for(long long i =0;i<6;i++) 13 13 states[0][i]=0; 14 14 /*6種狀態 15 15 * 0--剩013 16 16 * 1--剩13 17 17 * 2--剩01 18 18 * 3--剩3 19 19 * 4--剩1 20 20 * 5--無 21 21 */ 22 22 for(long long i=1;i<=n;i++) 23 23 { 24 24 long long j = i-1; 25 25 states[i][0] = 1; 26 26 states[i][1] = (states[j][0] + states[j][1] * 2) % mod; 27 27 states[i][2] = (states[j][0] + states[j][2]) % mod; 28 28 states[i][3] = (states[j][1] + states[j][3] * 2) % mod; 29 29 states[i][4] = (states[j][1] + states[j][2] + states[j][4] * 2) % mod; 30 30 states[i][5] = (states[j][3] + states[j][4] + states[j][5] * 2) % mod; 31 31 } 32 32 cout<<states[n][5]<<endl; 33 33 return 0; 34 34 }
很奇怪,測試時得分只有30,我選取了幾組數據和答案對比都一樣,而用答案測試的時候得分直接是0 -.-||
******************************更新*******************************
評論指出是我聲明的類型太小了,改了以后果然正常了!!!!感謝感謝!