1. 程式人生 > >CCF模擬題——有趣的數詳解

CCF模擬題——有趣的數詳解

馬上就要參加CCF認證考試了,然後最近就在做CCF上的模擬題,我選的語言是java,然後遇到第四題——有趣的數,當時一看題目,臥槽太TM簡單了,比第一題和第二題還簡單,高興死我了,然後我就做唄,然後我就做完了,然後就交了,然後就跪了(這個事實證明我們不能亂立flag),然後我發現並不是我演算法錯了,就是稍微有點久(其實是非常久吧,喂!),反正就是沒達到時間要求啦,然後我就查網上,查到幾個但是沒用,也不說思路的(作者你出來,我保證不~打死你)。後來在逛這個論壇的看見有人問這個,然後下面有位大神給了一種思路,我琢磨了一下,臥槽,大神太屌了,雖然沒怎麼認真說,但是我還是看懂了,我現在大二,程式設計才1年,我能看懂,你們也能看懂。

給題目先:

我們把一個數稱為有趣的,當且僅當:

1. 它的數字只包含0, 1, 2, 3,且這四個數字都出現過至少一次。

2. 所有的0都出現在所有的1之前,而所有的2都出現在所有的3之前。

3. 最高位數字不為0。

因此,符合我們定義的最小的有趣的數是2013。除此以外,4位的有趣的數還有兩個:2031和2301。

請計算恰好有n位的有趣的數的個數。由於答案可能非常大,只需要輸出答案除以1000000007的餘數。

這道題最後我是用動態規劃解的,嗯?你問我什麼是動態規劃?我也想知道啊喂!!人家昨天才碰到的這個題~~

哎呀反正你能懂怎麼出來答案的就行了唄!

首先來看程式碼:

long mod = 1000000007;

Scanner sc = new Scanner(System.in);
int number = sc.nextInt();
long [][] status = new long[number + 1][6];
for (int i = 0; i < 6; i ++)
status[0][i] = 0;


for (int i = 1; i < number + 1; i ++){
status[i][0] = 1;
status[i][1] = (status[i - 1][1] * 2 + status[i - 1][0]) % mod;
status[i][2] = (status[i - 1][2] + status[i - 1][0]) % mod;
status[i][3] = (status[i - 1][3] * 2 + status[i - 1][1]) % mod;
status[i][4] = (status[i - 1][4] * 2 + status[i - 1][2] + status[i - 1][1]) % mod;
status[i][5] = (status[i - 1][5] * 2 + status[i - 1][4] + status[i - 1][3]) % mod;
}
System.out.println(status[number][5]);

首先我們還是得從題目分析

0不能再首位是吧?那首位只能是1,2,3中的一個唄是吧?你放1看看行不,肯定不行啊,所有0得在1的前面,你放1了讓0情何以堪?放2可以,放3的話你讓2情何以堪?

所以首位只能放2對吧?

現在來說status這個二維陣列,status[i][j]到第i個位置滿足第j種狀態的所有可能數,總共最多有6種狀態:

0 -- 0 1 (2) 3
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)

比如說status[5][4] = 70的意思就是,到第5位(首位是第1位!)為止,保持第4種狀態的數一共有70個(咳咳,當然資料是我瞎掰的)

在括號裡的數說明前面的k位中,只出現了括號裡的數,你可以發現6個狀態中2都是被括號括起來的,沒辦法,剛剛說了2必須是首位啊

而且這是你在填第k+1位的時候能保持的僅有的6個狀態,其他的狀態都是無效的

比如0(1)(2) 3就是無效的,那是不可能的啊,假如說你現在填的是第k位吧,那麼你填完第k位的數後的狀態是隻包括1和2,那你想想,怎麼可能只出現1和2呢?那你讓0情何以堪?0就沒地方放了。

第一個for迴圈不講

第二個for迴圈n次だろ?很明顯這個就對應n位

然後看第一個式子

status[i][0] = 1;

到第i位為止,第i位填的數字使整個數字要滿足狀態0,那麼這樣的可能有幾個?1個唄,你要能填出2以外的數來我就去(qia shi la)

status[i][1] = (status[i - 1][1] * 2 + status[i - 1][0]) % mod;

到第i位為止,填第i位的數,使整個數保持狀態1。要滿足狀態1,也就是隻出現0和2,那你想前i-1位應該是個什麼狀態,要麼是隻有2,要麼是0,2對吧?就兩種狀態

然後如果前i-1位是狀態0的話(只有2),那你這一位只能填0了嘛,所以status[i - 1][0]就是這樣來的,如果前i-1位是狀態1(有0,2),那麼你現在有兩種選擇,填0或者是2兩種情況,status[i - 1][1] * 2就是這樣來的,然後把兩種情況相加,就表示到第i位為止,狀態為1的數共有status[i][1]這麼多個

然後後面的都差不多啦,因為每一位可能會進入6種不同的狀態,所以都要算出來

最後輸出System.out.println(status[number][5]),因為題目要求0,1,2,3必須至少出現一次,所有我們要輸出狀態5的數的個數

每次都求餘,這個很好理解吧?因為題目只要求求餘數就可以了呀,中間結果不斷取餘不會有影響的

我希望能幫到你們,CCF加油啦

對了我是用java寫的