先上代码
#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上的测试用例可能是根据错误的代码得出的,测试用例大概率是不正确的。
不保证结论正确,如果有问题希望指出,谢谢。