HDU-1005 Number Sequence(矩阵快速幂或模拟)

算是一道矩阵基础题吧,总之是对我很有启发性的一个矩阵题,之后类似的题估计都可以有这个思路,当然,这题也可以模拟出来。

    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). 
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


题意是:给出一个递推公式,求第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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值