Number Sequence(hdoj1005)

本文探讨了一类特定数列的快速求解方法,通过发现数列中的周期性规律,利用循环特性有效解决了大规模数值计算的问题。文中提供了三种不同的实现方案,并附带了完整的代码示例。

Number Sequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 178776 Accepted Submission(s): 44428

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

Author

CHEN, Shunbao

Source

ZJCPC2004

思路

尝试了下循环n次求解f(n),超时。
观察到f(n)在[0,6]之间,数字是很神奇的,会产生循环,且a和b是固定的,f(n)可由f(n-1)和f(n-2)来确定。在判断周期时,只需判断存在f(i)=f(i+T)和f(i-1+T)=f(i-1),即可知道周期为T。

注意f(n)可能存在这种情况:1 1 2 3 4 5 2 3 4 5,f(1)和f(2)不在循环里(一开始卡在这一直超时)
AC代码一

#include<iostream>  
#include<stdio.h>  
using namespace std;
int g[100000002];
int main()
{
    int fn1, fn2, fn,s;
    int a, b, n,j;
    while (scanf("%d%d%d", &a, &b, &n)!=EOF && a+b+n) {
        fn1 = fn2 = fn = 1;
        g[1] = g[2] = 1;
        s = 0;

        for (long i = 3; i <= n; i++)
        {
            fn = (a * fn1 + b * fn2) % 7;

            g[i] = fn;
            for ( j = 2; j<i; j++)
                if (g[i - 1] == g[j - 1] && g[i] == g[j])//此题可以这样做的原因就是 2个确定后就可以决定后面的  
                {
                    s = i - j;
                    //cout<<j<<" "<<s<<" >>"<<i<<endl;  
                    break;
                }
            /*if (fn == 1 && fn1 == 1) {
                s = i - 1;
            }*/
            if (s != 0)
            {
                fn = g[(n-j)%s+j];
                break;
            }
            fn2 = fn1;
            fn1 = fn;
        }
        printf("%d\n", fn);    
    }
    return 0;
}


进行一次优化

#include<iostream>  
#include<stdio.h>  
using namespace std;
int g[48 + 5];
int main()
{
    int a, b, n, s;
    long i;
    while (scanf("%d%d%d", &a, &b, &n) != EOF && a + b + n) {
        g[1] = g[2] = 1;
        s = 0;
        for (i = 3; i <= n; i++)
        {
            g[i] = (a * g[i - 1] + b * g[i - 2]) % 7;
            if ((i>4) && g[i] == g[4] && g[i - 1] == g[3]) {
                s = i - 4;
            }
            if (s != 0)
            {
                g[0] = g[(n - 4) % s + 4];
                break;
            }
        }
        printf("%d\n", i>n ?  g[n]: g[0] );
    }
    return 0;
}


第二种方案求周期

有个非常坑的地方:f[k++]一直给我wa,我换成f[k],k++,才ac。

AC代码

#include <iostream>  
#include <stdio.h>  
#include <string.h>  
using namespace std;
const int N = 100;
int f[N], m[8][8];
int main()
{
    int n, a, b, k = 3,s,x;
    while (scanf("%d%d%d", &a, &b, &n) != EOF && a + b + n)
    {
        k = 3;
        memset(m, 0, sizeof(m));
        f[1] = f[2] = 1;
        while (!m[f[k - 1]][f[k - 2]])
        {
            m[f[k - 1]][f[k - 2]] = k;
            f[k] = (a*f[k - 1] + b*f[k - 2])%7;
            k++;
        //    printf("f(%d)=%d ", k - 1, f[k - 1]);            
        }    
        x = m[f[k - 1]][f[k - 2]];
    //    printf("\ns=%d f[0]=%d\n", s, f[0]);
        printf("%d\n", n < k ? f[n] : f[(n - (x)) % (k - x) + (x)]);
    }
}

第三种网上贼屌的代码

#include<stdio.h>  
int main()  
{  
    int a,b,n,i,arr[49]={1,1};  
    while(scanf("%d%d%d",&a,&b,&n)&&(a|b|n))  
    {  
        for(i=2;i<49;i++)  
            arr[i]=(a*arr[i-1]+b*arr[i-2])%7;  
        printf("%d\n",arr[(n-1)%49]);//数组下标从0开始,所以n先减1  
    }  
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值