杭电1005

探讨了一个模7数列的循环周期问题,通过分析数列特性,找到了一种有效的方法来计算特定项的值,同时指出了一些常见的误解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Description
A number sequence is defined as follows:

f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.

Given A, B, and n, you are to calculate the value of f(n).

Input
The input consists of multiple test cases. Each test case contains 3 integers A, B and n on a single line (1 <= A, B <= 1000, 1 <= n <= 100,000,000). Three zeros signal the end of input and this test case is not to be processed.

Output
For each test case, print the value of f(n) on a single line.

Sample Input
1 1 3
1 2 10
0 0 0

Sample Output
2
5

第一反应递归,但是n可能是一个很大的值,这时候,资源就不够了,所以还是要找到其他的解题途径。
注意到:每一个f(n),只会受到f(n-1)跟f(n-2)的影响,所以。当连续的两个f值与之前任意的连续的两个f值重复的话,就说明后面肯定是一样的了。
如:a,b,……c,d,a,b……可以知道a,b……c,d肯定是一个循环节(可能不是最小的循环节)。接下来看看最长的循环有多长。模7运算,只有可能出现0~6这7个数,这样连续的两个数值对共有7*7=49种。又每个由于可能会有f(1),f(2)与f(2),f(3)对应相等的情况,故总共48位数就可以容下这49种情况了。这49种情况是最理想的状态,相互间的取值互不干扰的。一般情况下,循环节的长度都是要比48小的。所以可以只计算前个48f值,存下来,然后我们试着寻找循环周期的长度,它的开始位置,最后可以按要求的输出。

#include <stdio.h>

int main()
{
    int A,B,flag,period,i,j;
    int n,index;
    int fn[48];

    while(scanf("%d %d %ld",&A,&B,&n)!=EOF)
    {
        if(A==0&&B==0&&n==0)
            break;

        index = n-1;
        fn[0] = 1;
        fn[1] = 1;

        flag = 0;

        for(int t=2;t<48;t++)
        {//算前48位
            fn[t] = (A*fn[t-1] + B*fn[t-2])%7;
        }

        for(i=0;i<46;i++)
        {//比较每连续的两位
            for(j=i+1;j<48;j++)
            {
                if(fn[i]==fn[j]&&fn[i+1]==fn[j+1])
                {//找到了重复的连续两位
                    flag = 1;
                    break;
                }
            }
            if(flag==1)
            {
                 period = j-i;
                 break;
            }
        }

        if(index>=48)
            index = (index-i) % period;

        printf("%d\n",fn[index]);
    }
    return 0;
}

这样写无法通过,是wrong answer

在网上看到了一些帖子,都说要这么写

#include <stdio.h>

int main()
{
    int A,B,flag,period,i,j;
    int n,index;
    int fn[48];

    while(scanf("%d %d %ld",&A,&B,&n)!=EOF)
    {
        if(A==0&&B==0&&B==0)
            break;


        index = n-1;
        fn[0] = 1;
        fn[1] = 1;

        flag = 0;

        for(int t=2;t<48;t++)
        {
            fn[t] = (A*fn[t-1] + B*fn[t-2])%7;
        }


        index = index % 48;

        printf("%d\n",fn[index]);
    }
    return 0;
}

果然ac了。
但是,这样的就表示48是所有情况下的循环节的公倍数,而且这种循环都是以1,1两个连续数开头的,是这样吗?
这里写图片描述
这个是A=1,B=5的情况,我手算了一遍,跟程序的结果对比了一下,发现周期是21,48不可能是它的倍数。在n=49的时候,ac的那个程序给出的是1,也就是f(1)的结果,而我原本写的那个是0,二者不一样,肯定有一个是错的。
核对之前的数列,可以确定我的结果的正确性。因此,可以确定这道题测试数据有问题。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值