hdu 1005 Number Sequence(两种方法,鸽巢原理寻找循环节, 矩阵快速幂)
题目链接: hdu 1005 Number Sequence
题目描述: f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.
给出A ,B,N求出f(n);
题解思路:
方法1:
鸽巢原理(狄利克雷抽屉原理): 维基百科:鸽巢原理
因为 f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.所以f(n)的取值范围是【0,6】7中可能,所以说f(n - 1)和f(n - 2)各有7中可能,因为任意f(n - 1)和f(n - 2)对应唯一的f(n)所以当数列中出现两对相等的f(n - 1)和f(n - 2)那么根据f(n)的唯一性,那么递推下去就必然出现周期性,因为f(n - 1) , f(n - 2)的组合情况有7 * 7 = 49 种所以周期在50以内。
这种方法我看网上有争议的地方,==有关这个循环节是否一定是从1开始,==如果是的话,那么只要算50多组数据找到第二次出现1和1就可以找到周期,这样提交的代码可以AC,但是有人说这样不对,要用循环来找到循环节,我认为循环节一定从1开始,因为 如果知道f(n)和f(n - 1)那么就可以对应到唯一的一个f(n - 2)所以所有的数都是相关联的, 那么必然从1开始就是周期,如果有人可以说清楚为什么循环节不一定从1开始,希望可以私信我。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int ans[100];
int main()
{
int a, b, n;
int pos = 0;
while(1){
cin >> a >> b >> n;
if(a == 0 && b == 0 && n == 0){
break;
}
ans[1] = ans[2] = 1;
for(int i = 3; i < 100; i++){
ans[i] = (a * ans[i - 1] + b * ans[i - 2]) % 7;
}
for(int i = 3; i < 100; i++){
if(ans[i] == 1 && ans[i + 1] == 1){
pos = i;
}
}
if(n < 100){
cout << ans[n] << endl;
}
else{
cout << ans[n % (pos - 1)] << endl;
}
}
return 0;
}
方法2:
矩阵快速幂:
f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7
根据上面这个迭代式,可以的出这样一个矩阵的关系式:
| f(n) | -------> |A B| | f(n - 1) |
| f(n - 1) | -------> |1 0| | f(n - 2) |
所以问题的求解可以看成矩阵的乘法,那么由f(1)和f(2)推到f(n)只要运用矩阵的快速幂求解即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
struct Matrix{
int m[2][2];
Matrix(){
memset(m, 0, sizeof(m));
}
};
Matrix multi(Matrix a, Matrix b)
{
Matrix ans;
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){
for(int k = 0; k < 2; k++){
ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j]) % 7;
}
}
}
return ans;
}
Matrix fast_pow(Matrix a, int n)
{
Matrix res;
for(int i = 0; i < 2; i++){
res.m[i][i] = 1;
}
while(n){
if(n % 2 == 1){
res = multi(res, a);
}
n = n / 2;
a = multi(a, a);
}
return res;
}
int main()
{
int a, b, n;
Matrix ans;
while(1){
cin >> a >> b >> n;
if(n == 1 || n == 2){
cout << "1" << endl;
continue;
}
if(a == 0 && b == 0 && n == 0){
break;
}
Matrix x;
x.m[0][0] = a;
x.m[0][1] = b;
x.m[1][0] = 1;
x.m[1][1] = 0;
ans = fast_pow(x, n - 2);
cout << (ans.m[0][0] + ans.m[0][1]) % 7 << endl;
}
return 0;
}
该博客介绍了两种方法解决数列递推问题,包括利用鸽巢原理寻找循环节以及使用矩阵快速幂算法。第一种方法通过分析f(n)的取值范围和递推关系,确定循环节的存在并寻找其开始位置。第二种方法通过矩阵乘法将递推关系转化为矩阵运算,利用矩阵快速幂高效求解。这两种方法都针对HDU1005NumberSequence题目,适用于模7的线性递推序列。
&spm=1001.2101.3001.5002&articleId=112911565&d=1&t=3&u=fb1c3b1bda97426bb9a630b6cb157c32)
313

被折叠的 条评论
为什么被折叠?



