先上代碼
#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上的測試用例可能是根據錯誤的代碼得出的,測試用例大概率是不正確的。
不保證結論正確,如果有問題希望指出,謝謝。