算是一道矩阵基础题吧,总之是对我很有启发性的一个矩阵题,之后类似的题估计都可以有这个思路,当然,这题也可以模拟出来。
Number Sequence HDU-1005
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).
1 1 3 1 2 10 0 0 0
2 5
题意是:给出一个递推公式,求第n个数。
思路:遇到这种题,直接想的能否找到一个直接求解的递推公式,很遗憾没找到,所以去考虑矩 阵快速幂。
因为矩阵相乘是满足结合律的,所以上面的式子是可以得到正确结果的。
AC代码1
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
int n, a, b;
struct node{
int a, b, c, d;
};
node multi(node x, node y){
node res;
res.a = (x.a*y.a + x.b*y.c)%7;
res.b = (x.a*y.b + x.b*y.d)%7;
res.c = (x.c*y.a + x.d*y.c)%7;
res.d = (x.c*y.b + x.d*y.d)%7;
return res;
}
int quickm(int n){
node base, ans;
base.a = a, base.b = b, base.c = 1, base.d = 0;
ans.a = ans.d = 1, ans.b = ans.c = 0;;
while(n){
if(n&1){
ans = multi(ans, base);
}
base = multi(base, base);
n >>= 1;
}
return (ans.a+ans.b)%7;
}
int main(){
ios::sync_with_stdio(0);
while(cin >> a >> b >> n){
if(a == 0 && b == 0 && n == 0) break;
if(n == 1 || n == 2){
cout << 1 << endl;
continue;
}
cout << quickm(n-2) << endl;
}
return 0;
}
当然,这题也可以通过模拟出来的。
对于公式 f[n] = A * f[n-1] + B * f[n-2];后者只有7 * 7 = 49 种可能,为什么这么说,因为对于f[n-1]
或者 f[n-2] 的取值只有 0,1,2,3,4,5,6 这7个数,A,B又是固定的,所以就只有49种可能值了。由该关系
式得知每一项只与前两项发生关系,所以当连续的两项在前面出现过循环节出现了,注意循环节并不一
定会是开始的 1,1 。 又因为一组测试数据中f[n]只有49中可能的答案,最坏的情况是所有的情况都遇到
了,那么那也会在50次运算中产生循环节。找到循环节后,就可以轻松解决了。
AC代码2
#include <iostream>
#include <cstdio>
using namespace std;
int jk[55];
int main(){
ios::sync_with_stdio(0);
int i, j, x, y, z, a, b, n;
while(cin >> a >> b >> n){
if(a == 0 && b == 0 && n == 0) break;
if(n == 1 || n == 2){
cout << 1 << endl;
continue;
}
jk[1] = jk[2] = 1;
for(i = 3; i <= n; ++i){
jk[i] = (a*jk[i-1]+b*jk[i-2]) % 7;
for(j = 2; j < i; ++j){
if(jk[j-1] == jk[i-1] && jk[j] == jk[i]){
x = j-1, y = i-2;
break;
}
}
if(i != j) break;
}
if(i > n) cout << jk[n] << endl;
else{
z = y-x+1;
i = y;
while(i+z < n) i += z;
cout << jk[x+n-i-1] << endl;
}
}
return 0;
}