A - Number Sequence(矩阵快速幂或者找周期)
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).
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
问题:arr[1] = 1; arr[2] = 1; arr[i] = A*arr[i-2]+B*arr[i-1];
测试案例有若干项,每个案例给出A, B, n,输出arr[n]的值
输入以0,0,0结束
分析:这种有规律的序列都是有周期的,
每输入一组数据,计算出一个周期内的所有的数,和周期大小
输入n之后就可以找出第n项了
因为每一项只能是 1~7 之间的数字,而后一项又与前两项有关,所以周期为A(7, 2)
分析到这里我们就可以介绍下面两种方法了
Ⅰ方法一,矩阵快速幂算类似于斐波那契数列
对于这样的数列:
f(1) = a, f(2) = b, f(n) = A * f(n - 2) + B * f(n - 1). 可以用以下方法求f(n)
我们注意到从第三项开始
(可以在演草纸上算出)
从第三项开始,我们可以先算出,然后用结果矩阵的上边的元素作为计算的f(n)
比如
那么f(n) = a[0][0]*b + a[0][1]*a;
Ⅱ 方法二:
我们已经分析了这个数列是又周期的,周期为42,因为f(1) = 1, f(2) = 1
所以,当再次遇到1, 1的时候,就已经找到所有的答案了
用一个数组存储这个数列一个周期里的结果,输出即可
方法分析:如果我们没有算出这个数列的周期,而且我们不确定这个周期到底多大,那么可以采用第一种方法,
因为这种情况如果采用第二种方法就可能出现开的存储一个周期内数据的数组太小的情况,
现在我们既然知道周期了,当然是第二种方法比较简单
但是我真心不知道为什么我用第二种方法的时候竟然和我开的数组大小有关,M = 50对,M = 10000对,还有一些数据对,但是M为其他数就不对了
我就郁闷了,和我开的数组大小有毛线关系
代码1:
#include <cstdio> #include <cstring> #define N 2 struct Mat { int arr[N][N]; }; //定义矩阵 Mat multiply(Mat x, Mat y)//矩阵乘法 { Mat res; memset(res.arr, 0, sizeof(res.arr)); for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) { for(int k = 0; k < N; k++) { res.arr[i][j] += x.arr[i][k] * y.arr[k][j]; //res.arr[i][j] %= 7; } } } return res; } Mat cacl(Mat a, int n) //矩阵快速幂,算a的n次方 { Mat res; for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) res.arr[i][j] = (i == j); } while(n) { if(n & 1) res = multiply(res, a); n /= 2; a = multiply(a, a); } return res; } int main() { int A, B, n; Mat a; while(scanf("%d%d%d", &A, &B, &n), (A || B || n)) { a.arr[0][0] = A; a.arr[0][1] = B; a.arr[1][0] = 1; a.arr[1][1] = 0; n %= 42; if(n == 1 || n == 2) printf("1\n"); else { Mat tmp = cacl(a, n-2); int ans = (tmp.arr[0][0] + tmp.arr[0][1]) % 7; printf("%d\n", ans); } } return 0; }
方法二代码:
#include <stdio.h> #define M 10000 int cacl(int arr[], int A, int B) { int i; arr[1] = arr[2] = 1; for(i = 3; i<= M-1; i++) { arr[i] = (A*arr[i-1] + B*arr[i-2]) % 7; //printf("arr[%d] = %d\n", i, arr[i]); if(arr[i] == 1 && arr[i-1] == 1) break; } arr[0] = arr[i-2]; return (i-2); } int main() { int arr[M]; int A, B, n; int T; while(scanf("%d%d%d", &A, &B, &n), (A||B||n)) { T = cacl(arr, A, B); //printf("T = %d\n", T); n %= T; printf("%d\n", arr[n]); } return 0; }