杭电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上的测试用例可能是根据错误的代码得出的,测试用例大概率是不正确的。

不保证结论正确,如果有问题希望指出,谢谢。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值