ZCMU-1184 帮我求算一下斐波那契数吧(矩阵快速幂+应用)

1184: 帮我求算一下斐波那契数吧

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 261  Solved: 57
[Submit][Status][Web Board]

Description

AYY小朋友对斐波那契数非常感兴趣,他知道f[1]=1,f[2]=1,并且从第三个斐波那契数开始f[n]=f[n-2]+f[n-1](n>=3),可是AYY小朋友只会计算前十个斐波那契数,因此他向你请教,让你帮忙计算第N个斐波那契数是多少,但是由于结果非常大,只需告诉他对1000000007取模的结果。

 

Input

多组测试数据

每行一个n(1<=n<=2^32-1)

 

Output

输出第n个斐波那契数的结果(对1000000007取模)

 

Sample Input

1

10

100

1000

10000

Sample Output

1

55

687995182

517691607

271496360

HINT

Source

 

【解析】

如果每次用递推公式,显而易见是会超时的 (1<=n<=2^32-1),预处理打表的话,上亿肯定内存超限了。那就只能引入新方法,快速幂矩阵了。

之前已经了解过整数快速幂了,则用相似的原理,矩阵也能快速幂

直接先看代码的实现

struct Matrix
{
	int a[maxn][maxn];
}ans, res;
Matrix Mulit(Matrix A, Matrix B, int n)//矩阵A,B为同n阶方阵
{
	Matrix temp;//用于存放A*B的结果
	memset(temp.a, 0, sizeof(temp.a));
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			for (int k = 1; k <= n; k++)
				temp.a[i][k] += A.a[i][k] * B.a[k][j];
	return temp;
}

void QuickPower(int N, int n)
{
	memset(ans.a, 0, sizeof(ans.a));
	for (int i = 1; i <= n; i++)ans.a[i][i] = 1;
	while (N)
	{
		if (N & 1)
			ans = Mulit(ans, res, n);
		res = Mulit(res, res, n);
		N = N >> 1;
	}
}

如何运用呢,最经典的用法就是此题。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 4;
const ll mod = 1000000007;
struct Matrix
{
	ll m[maxn][maxn];
}ans,res;

Matrix Mulit(Matrix a, Matrix b, ll n)
{
	Matrix temp;
	for (ll i = 1; i <= n; i++)
		for (ll j = 1; j <= n; j++)
			temp.m[i][j] = 0;
	for (ll i = 1; i <= n; i++)
		for (ll j = 1; j <= n; j++)
			for (ll k = 1; k <= n; k++)
				temp.m[i][j] = (temp.m[i][j] + ((a.m[i][k] % mod) * b.m[k][j]%mod)) % mod;
	return temp;
}

ll QuickPower(ll N, ll n)
{
	for (ll i = 1; i <= n; i++)
		for (ll j = 1; j <= n; j++)
		{
			if (i == j)ans.m[i][j] = 1;
			else ans.m[i][j] = 0;
		}
	memset(res.m, 0, sizeof(res.m));
	res.m[1][1] = 1;
	res.m[1][2] = 1;
	res.m[2][1] = 1;
	res.m[2][2] = 0;
	while (N)
	{
		if (N & 1)
			ans = Mulit(ans, res, n);
		res = Mulit(res, res, n);
		N = N >> 1;
	}
	Matrix ok;
	ok.m[1][1] = ok.m[2][1] = 1;
	ok.m[1][2] = ok.m[2][2] = 0;
	ok = Mulit(ans, ok, n);
	return ok.m[1][1];
}


int main()
{
	ll n;
	while (~scanf("%lld", &n))
	{
		if (n <= 2)
			printf("1\n");
		else
			printf("%lld\n", QuickPower(n - 2, 2));
	}

	return 0;
}

 

### zcmu Java 题解与代码实现 在讨论与 zcmu 相关的 Java 内容时,可以参考一些常见的法题解和代码实现。以下是基于提供的引用内容以及其他知识背景生成的内容。 #### 1. Java 实现字符串头尾相连问题 此问题的核心在于判断一个字符串是否可以通过头尾相连后形成回文串。通过将字符串复制并反转,检查原字符串是否为反转后字符串的子串来实现[^5]。 ```java import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int t = scanner.nextInt(); scanner.nextLine(); // 清除换行符 while (t-- > 0) { String xl = scanner.nextLine(); String s = xl + xl; // 将字符串复制一遍 StringBuilder reversed = new StringBuilder(s).reverse(); // 反转字符串 if (reversed.toString().contains(xl)) { // 判断是否包含原字符串 System.out.println("YES"); } else { System.out.println("NO"); } } } } ``` #### 2. Java 实现最短路径问题 对于类似灯塔覆盖范围的问题,可以通过遍历所有灯塔并更新可达范围来解决。如果能够到达终点且返回起点,则答案为 `(终点 - 起点) * 3`,否则输出 `-1`[^3]。 ```java import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int t = scanner.nextInt(); while (t-- > 0) { int n = scanner.nextInt(); long startX = scanner.nextLong(); long startR = scanner.nextLong(); long m = startX + startR; boolean canReach = true; for (int i = 1; i < n; i++) { long x = scanner.nextLong(); long r = scanner.nextLong(); if (x <= m && x + r > m) { m = x + r; } else if (x > m) { canReach = false; break; } } if (!canReach || startX > m) { System.out.println("-1"); continue; } m = startX - startR; for (int i = n - 2; i >= 0; i--) { long x = scanner.nextLong(); long r = scanner.nextLong(); if (x >= m && x - r < m) { m = x - r; } else if (x < m) { canReach = false; break; } } if (!canReach || startX < m) { System.out.println("-1"); } else { System.out.println((startX - startX) * 3); } } } } ``` #### 3. Java 实现字符串统计问题 对于字符串统计问题,可以使用 `HashMap` 来记录每个字符串出现的次,并找到出现次最多的字符串[^2]。 ```java import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNextInt()) { int n = scanner.nextInt(); if (n == 0) break; Map<String, Integer> map = new HashMap<>(); for (int i = 0; i < n; i++) { String str = scanner.next(); map.put(str, map.getOrDefault(str, 0) + 1); } String result = ""; int maxCount = 0; for (Map.Entry<String, Integer> entry : map.entrySet()) { if (entry.getValue() > maxCount) { maxCount = entry.getValue(); result = entry.getKey(); } } System.out.println(result); } } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值