HDU1005 Number Sequence 找循环周期

来源:互联网 发布:淘宝追加了评论看不见 编辑:程序博客网 时间:2024/06/01 08:36


Number Sequence(点击此传送至原题)


看到n的数据范围为1 – 100000000 ,并且可以输入多组数据,如果每次都用枚举的话必定超时。我们就想想这道题能不能通过找周期,把n的值缩小呢?


首先,A%7有7种情况,B%7有7种情况,那么A、B总共有49种情况,如果这49种情况都存在周期的话,那么我们就可以把每种情况的最小正周期求出来,再对n进行缩小,那么我们就可以减少大量的运算。


如何证明这49种情况是否都存在周期呢,我们试着用代码来实现。不过怎么知道某种情况下存在周期呢?假设周期为T,那么如果对于任意x( ),都有f(T + x) = f(x),我们就能得出这种情况在定义域D内存在周期且周期为T,对于这道题,只要我们找到一个整数T,使f(T + 2) = f(2), f(T + 1) = f(1),那么有f(T + 3) = (A * f(T + 2) + B * f(T + 1)) % 7 = (A * f(2) + B * f(1)) % 7 = f(3),同样地,我们有f(T + 4) = f(4), f(T + 5) = f(5)……那么有f(T + x) = f(x),即这种情况下f(x)存在周期T。因此,对于任意的A、B,只要能找到一个整数T,使f(T + 2) = f(2), f(T + 1) = f(1),那么就可以通过找周期来做这道题了。


#include <stdio.h>#define X 100000001 // X不论何值都存在找不到周期的情况的int a[X] = {0, 1, 1}, b[49][2];int main() {    int sum = 0, num = 0, max = 0;    for(int i = 0; i < 7; i++) {        for(int j = 0; j < 7; j++) {            int k = 3;            while(k < X) {                a[k] = (i * a[k - 1] + j * a[k - 2]) % 7;                if(a[k] == a[2] && a[k - 1] == a[1])//此时T = k - 2                    break;                k++;            }            if(k < X) {                printf("找到周期了,此时 a %% 7 = %d, b %% 7 = %d, 周期为 %d\n", i, j, k - 2);                sum++;                if(k - 2 > max)                    max = k - 2;            }            else {                printf("无法在%d内找到周期,此时 a %% 7 = %d, b %% 7 = %d\n", X - 1, i, j);                b[num][0] = i;                b[num][1] = j;                num++;            }        }    }    if(sum == 49)        printf("所有情况都能找到周期,周期最大为%d\n", max);    else {        printf("并非所有情况都能在%d内找到周期\n", X - 1);        for(int i = 0; i < num; i++)            printf("a %% 7 = %d, b %% 7 = %d时无法找到周期\n", b[i][0], b[i][1]);    }    return 0;}

 


代码运行后,我们发现当a % 7 != 1, b % 7 == 0的时候,存在找不到周期的情况。那么是不是说不能通过找周期来做呢?


我们先试着把a % 7 != 1, b % 7 == 0的时候f(x)前20项打印出来看看是什么原因导致找不到周期。

#include <stdio.h>int main() {    int f[25] = {0, 1, 1};    for(int i = 0; i < 7; i++) { //注意我这里用i来表示A % 7        if(i == 1)            continue;        printf("A %% 7 = %d, B %% 7 = 0时, f(x)前20项如下: 1 1", i); //无论A, B为多少f(1)=f(2)=1        for(int j = 3; j <= 20; j++)            printf(" %d", f[j] = i * f[j - 1] % 7);  //B * f(j - 2)在这里可以省略, 因为B % 7 = 0        printf("\n");    }    return 0;}


A % 7 = 0, B % 7 = 0时, f(x)前20项如下: 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

A % 7 = 2, B % 7 = 0时, f(x)前20项如下: 1 1 2 4 1 2 4 1 2 4 1 2 4 1 2 4 12 4 1

A % 7 = 3, B % 7 = 0时, f(x)前20项如下: 1 1 3 2 6 4 5 1 3 2 6 4 5 1 3 2 6 4 5 1

A % 7 = 4, B % 7 = 0时, f(x)前20项如下: 1 1 4 2 1 4 2 1 4 2 1 4 2 1 4 2 1 4 2 1

A % 7 = 5, B % 7 = 0时, f(x)前20项如下: 1 1 5 4 6 2 3 1 5 4 6 2 3 1 5 4 6 2 3 1

A % 7 = 6, B % 7 = 0时, f(x)前20项如下: 1 1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6 1 6 1


注意到,这6种情况f(x)并非对于都存在周期,而是对于x>2才存在周期,因此,我们应该在找周期时忽略掉f(1),f(2).


那么对于x>2 49种情况是否都能找到周期呢?显然,由于除上面讨论的6种情况对于x>2才存在周期以外,剩下的43种情况对于都存在周期,因此对于x>2同样存在周期,下面附上代码验证: (这里只需证明f(T + 4) = f(4), f(T + 3) = f(3) 即可说明f(x)(x > 2)存在周期且为T)

#include <stdio.h>#define X 53 // X >= 53 都能找到周期int a[X] = {0, 1, 1}, b[49][2];int main() {    int sum = 0, num = 0, max = 0;    for(int i = 0; i < 7; i++) {        for(int j = 0; j < 7; j++) {            a[3] = (i + j) % 7;            a[4] = (i * a[3] + j) % 7;            int k = 5;            while(k < X) {                a[k] = (i * a[k - 1] + j * a[k - 2]) % 7;                if(a[k] == a[4] && a[k - 1] == a[3])                    break;                k++;            }            if(k < X) {                printf("找到周期了,此时 a %% 7 = %d, b %% 7 = %d, 周期为 %d\n", i, j, k - 4);                sum++;                if(k - 4 > max)                    max = k - 4;            }            else {                printf("无法在%d内找到周期,此时 a %% 7 = %d, b %% 7 = %d\n", X - 1, i, j);                b[num][0] = i;                b[num][1] = j;                num++;            }        }    }    if(sum == 49)        printf("所有情况都能找到周期,周期最大为%d\n", max);    else {        printf("并非所有情况都能在%d内找到周期\n", X - 1);        for(int i = 0; i < num; i++)            printf("a %% 7 = %d, b %% 7 = %d时无法找到周期\n", b[i][0], b[i][1]);    }    return 0;}


后面附上我的代码:

#include <stdio.h>int main() {    int A, B, n, i;    int f[55] = {0, 1, 1};    while(scanf("%d%d%d", &A, &B, &n), A) {        A %= 7;        B %= 7;        f[3] = (A + B) % 7;        f[4] = (A * f[3] + B) % 7;        for(i = 5; i < n + 1; i++) { //判断条件是i < n + 1是因为当n < T + 4 (T为周期)时还没算出周期,而此时已经把f(n)算出来的,就没有必要再算周期了            f[i] = (A * f[i - 1] + B * f[i - 2]) % 7;            if(f[i] == f[4] && f[i - 1] == f[3]) {                n = (n - 3) % (i - 4) + 3; //注意 i - 4 才是周期,加3是因为f(3)才是周期的第一个数                break;            }        }        printf("%d\n", f[n]);    }    return 0;}

1 0
原创粉丝点击