杭電OJ 1005 測試用例問題

先上代碼

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    int a, b, n;
    int arr[49];
    while (scanf("%d %d %d%*c", &a, &b, &n), (a | b | n))
    {
        arr[1] = arr[2] = 1;
        for (size_t i = 3; i < 49; i++)
        {
            arr[i] = (a * arr[i - 1] + b * arr[i - 2]) % 7;
        }
        int result = arr[n % 49];
        printf("%d\n", result);
    }
    return 0;
}

這段代碼是參照Discuss裏面解題思路寫的,目前是可以AC的,只想AC的看到這裏就可以了。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

原理大概就是f(n)只有7個值:0,1,2,3,4,5,6,而f(n)是通過f(n-1)和f(n-2)得到的,所以類似於斐波那契數列,且一共至多有7*7=49種組合,由於f(1) = 1,f(2) = 1 ,所以出現f(x)=1,f(x+1)=1時就會出現循環了。

 

在杭電的Discuss裏面有人給出了一些用例,其結果和上面代碼給出的結果是不一樣的。仔細想果然存在一些問題。

1、無法證明循環的週期就是49,通過打表來看的話,週期有長有短,但是不一定就是49,如A和B都等於3的時候。

2、即使週期是49,但是f(1),f(2)的值都是1,f(50)的值不一定就等於1,如A和B都等於7的時候f(50),f(51)就是0。

3、當n爲49時,arr[49%49]=arr[0],但是arr[0]一直沒有賦值。

經過修改代碼如下,雖然長了一點,但是健壯性強了許多,能通過Discuss裏面的數據,不過不能AC了。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    int a, b, n;
    int arr[53];
    while (scanf("%d %d %d%*c", &a, &b, &n), (a | b | n))
    {
        arr[1] = arr[2] = 1;
        for (size_t i = 3; i < 53; i++)
        {
            arr[i] = (a * arr[i - 1] + b * arr[i - 2]) % 7;
        }
        //找到循環節點的位置
        int p = 5;
        for (; !(arr[3] == arr[p] && arr[4] == arr[p + 1]); p++)
        {
        }
        p = p - 3;
        arr[0] = (a * arr[p - 1] + b * arr[p - 2]) % 7;
        // arr1 arr2
        if (n > p)
        {
            arr[1] = (a * arr[0] + b * arr[p - 1]) % 7;
            arr[2] = (a * arr[1] + b * arr[0]) % 7;
        }
        int result = arr[n % p];
        printf("%d\n", result);
    }
    return 0;
}

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

如果要AC需要將代碼中 int result = arr[n % p]  中的p改成49,這明顯是錯誤的。

下面驗證一下,首先先打表,下面這段的打表的代碼

#include <stdio.h>
#include <stdlib.h>

int arr[99999999];
int main(int argc, char const *argv[])
{
    int a, b, n;
    while (scanf("%d %d %d%*c", &a, &b, &n), (a | b | n))
    {
        arr[1] = arr[2] = 1;
        for (size_t i = 3; i <= n; i++)
        {
            arr[i] = (a * arr[i - 1] + b * arr[i - 2]) % 7;
            printf("%lld\t%d\n", i, arr[i]);
        }
    }
    return 0;
}

輸入3,3,60這個組數據:

3 3 60
3       6
4       0
5       4
6       5
7       6
8       5
9       5
10      2
11      0
12      6
13      4
14      2
15      4
16      4
17      3
18      0
19      2
20      6
21      3
22      6
23      6
24      1
25      0
26      3
27      2
28      1
29      2
30      2
31      5
32      0
33      1
34      3
35      5
36      3
37      3
38      4
39      0
40      5
41      1
42      4
43      1
44      1
45      6
46      0
47      4
48      5
49      6
50      5
51      5
52      2
53      0
54      6
55      4
56      2
57      4
58      4
59      3
60      0

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

我們看到當a=3,b=3,n=49時,是以42爲一個週期的,並且f(49)的值應該是6,f(50)的值應該是5,如果用改過的代碼調試,結果是正確的。

而將p值改爲49,雖然可以AC但是f(49)的值卻爲4,f(50)的值爲1,和表上的結果不符。

用本篇的第一段代碼居然也能AC,也就是arr[0]沒被賦值的時候,這時arr[0]是一個非常大的數,且每次運行時都不一樣。

所以可以推測OJ上的測試用例可能是根據錯誤的代碼得出的,測試用例大概率是不正確的。

不保證結論正確,如果有問題希望指出,謝謝。

 

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