HDU 2065 "紅色病毒"問題 遞推題 (2011-1-1 16:39)

HDU 2065 "紅色病毒"問題 遞推題
2010-02-04 16:39

AC code:

#include <stdio.h>
int main()
{
    int t,i;
    _int64 n;
    int a[23]={0,2,6,20,72,72,56,60,12,92,56,0,52,12,56,40,92,32,56,80,32,52,56};
    int b[20]=      {20,72,72,56,60,12,92,56,0,52,12,56,40,92,32,56,80,32,52,56};
    while (scanf("%d",&t)!=EOF)
    {
        if (t==0)
            return 0;
        for (i=1;i<=t;i++)
        {
            scanf("%I64d",&n);
            if (n<=22)
                printf("Case %d: %d\n",i,a[n]);
            else 
            {
                n=(n-3)%20;
                printf("Case %d: %d\n",i,b[n]);
            }
        }
        printf("\n");
    }
    return 0;
}

問題分析
Problem Analyse 遞推題 

如果沒有任何條件限制,A、B、C、D組成長度爲n的字符串,其個數應該爲:4n。

因爲有了A、C需要出現偶數次的要求,就出現合法和不合法的不同分組。
在不合法的組裏,又有
1.A出現奇數次、C出現偶數次;
2.C出現奇數次、A出現偶數次;
3.A出現奇數次、C出現奇數次;
三種情況。

我們用數組
f[n][0]保存長度爲n,合法的字符串的個數。
f[n][1]保存長度爲n,僅A出現奇數次的字符串的個數。
f[n][2]保存長度爲n,僅C出現奇數次的字符串的個數。
f[n][3]保存長度爲n,A、C出現奇數次的字符串的個數。

f[n][0]
長度爲n-1的合法字符串在末尾加上一個B或者D,都可以變成長度爲n的合法字符串。
長度爲n-1的僅A出現奇數次的字符串再在末尾加上一個A,也可以變成合法字符串。
長度爲n-1的僅C出現奇數次的字符串再在末尾加上一個C,也可以變成合法字符串。
所以,f[n][0] = 2 × f[n-1][0] + f[n-1][1] + f[n-1][2];

f[n][1]
長度爲n-1的合法字符串在末尾加上A,都可以變成長度爲n的僅A出現奇數次的字符串。
長度爲n-1的僅A出現奇數次的字符串再在末尾加上一個B或者D,也可以變成僅A出現奇數次的字

符串。
長度爲n-1的A、C出現奇數次的字符串再在末尾加上一個C,也可以變成僅A出現奇數次的字符串


所以,f[n][1] = 2 × f[n-1][1] + f[n-1][0] + f[n-1][3];

f[n][2]
長度爲n-1的合法字符串在末尾加上C,都可以變成長度爲n的僅C出現奇數次的字符串。
長度爲n-1的僅C出現奇數次的字符串再在末尾加上一個B或者D,也可以變成僅C出現奇數次的字

符串。
長度爲n-1的A、C出現奇數次的字符串再在末尾加上一個A,也可以變成僅C出現奇數次的字符串


所以,f[n][2] = 2 × f[n-1][2] + f[n-1][0] + f[n-1][3];

f[n][3]
長度爲n-1的A、C出現奇數次的字符串在末尾加上一B或者D,都可以變成長度爲n的A、C出現奇數

次的字符串。
長度爲n-1的僅A出現奇數次的字符串再在末尾加上一個C,也可以變成A、C出現奇數次的字符串


長度爲n-1的僅C出現奇數次的字符串再在末尾加上一個A,也可以變成A、C出現奇數次的字符串


所以,f[n][3] = 2 × f[n-1][3] + f[n-1][1] + f[n-1][2];

綜上所述,我們得到:
f[n][0] = 2 × f[n-1][0] + f[n-1][1] + f[n-1][2]; ①
f[n][1] = 2 × f[n-1][1] + f[n-1][0] + f[n-1][3]; ②
f[n][2] = 2 × f[n-1][2] + f[n-1][0] + f[n-1][3]; ③
f[n][3] = 2 × f[n-1][3] + f[n-1][1] + f[n-1][2]; ④

f[1][0] = 2
f[1][1] = 1
f[1][2] = 1
f[1][3] = 0

發現f[1][1]與f[1][2]初始狀態相同,而且以後迭代方程也相同,所以f[n][1] = f[n][2]
又有f[n][0] + f[n][3] = f[n][1] + f[n][2]
∵f[n][0] + f[n][1] + f[n][2] + f[n][3] = 4n
∴f[n][0] + f[n][3] = f[n][1] + f[n][2] = 2 × 4n-1
∴f[n-1][1] + f[n-1][2] = 2 × 4n-2
∴f[n][0] = 2 × f[n-1][0] + f[n-1][1] + f[n-1][2] = 2 × f[n-1][0] + 2 × 4n-2

我們得到:
f[n][0] = 2 × f[n-1][0] + 22n-3
f[n-1][0] = 2 × f[n-2][0] + 22n-5

f[n-m][0] = 2 × f[n-m-1][0] + 22n-2m-3

f[2][0] = 2 × f[1][0] + 21
f[1][0] = 2

開始一層層往下迭代:
f[n][0]
= 2 × f[n-1][0] + 22n-3
= 22 × f[n-2][0] + 22n-4 + 22n-3

= 2m × f[n-m][0] + 22(n-m)-1+m-1 + ... + 22n-3
= 2n-1 × f[1][0] + 2n-1 + 2n +... + 22n-3
f[1][0] = 2;

∴f[n][0] = 2n + 2n-1 + 2n +... + 22n-3 = 22n-2 + 2n-1

算法實現

Programing 公式得到了:f(n) = 22n-2 + 2n-1
但就這樣直接編程那是不可能實現的,因爲n的範圍1≤N<264
怎麼的範圍,是不能求出f(n)的。所以還得找其他規律。
因爲題目只要求輸出最後2位數,我們依次輸出2的n的最後兩位看看...
20 -> 1
21 -> 2
22 -> 4
23 -> 8
24 -> 16
25 -> 32
26 -> 64
27 -> 28
28 -> 56
29 -> 12
210 -> 24
211 -> 48
212 -> 96
213 -> 92
214 -> 84
215 -> 68
216 -> 36
217 -> 72
218 -> 44
219 -> 88
220 -> 76
221 -> 52
222 -> 4
到了222時,末尾2位又變成4,與22一樣,這時候就進入了一個循環了(每20個一次循環)。
所以,結果只能是這22箇中的一個。只有n=0 和 n=1是需要特殊考慮的。其他n就等於2(n-2) %

20 + 2的值了。

原題:

"紅色病毒"問題

Time Limit: 1000/1000 MS (Java/Others)     Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1040     Accepted Submission(s): 408

Problem Description
醫學界發現的新病毒因其蔓延速度和Internet上傳播的"紅色病毒"不相上下,被稱爲"紅色病毒",經研究發現,該病毒及其變種的DNA的一條單鏈中,胞嘧啶,腺嘧啶均是成對出現的。
現在有一長度爲N的字符串,滿足一下條件:
(1) 字符串僅由A,B,C,D四個字母組成;
(2) A出現偶數次(也可以不出現);
(3) C出現偶數次(也可以不出現);
計算滿足條件的字符串個數.
當N=2時,所有滿足條件的字符串有如下6個:BB,BD,DB,DD,AA,CC.
由於這個數據肯能非常龐大,你只要給出最後兩位數字即可.

Input
每組輸入的第一行是一個整數T,表示測試實例的個數,下面是T行數據,每行一個整數N(1<=N<2^64),當T=0時結束.

Output
對於每個測試實例,輸出字符串個數的最後兩位,每組輸出後跟一個空行.

Sample Input
4
1
4
20
11
3
14
24
6
0

Sample Output
Case 1: 2
Case 2: 72
Case 3: 32
Case 4: 0

Case 1: 56
Case 2: 72
Case 3: 56

Author
Rabbit

Source

Recommend
lcy
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章