【Loj #10222. 「一本通 6.5 例 4」佳佳的 Fibonacci】题解

题目链接

题目

佳佳对数学,尤其对数列十分感兴趣。在研究完 Fibonacci 数列后,他创造出许多稀奇古怪的数列。例如用 S(n) 表示 Fibonacci 前 n 项和 modm 的值,即 S(n)=(F1+F2+...+Fn)modm,其中 F1=F2=1,Fi=Fi1+Fi2 。可这对佳佳来说还是小菜一碟。
终于,她找到了一个自己解决不了的问题。用 T(n)=(F1+2F2+3F3+...+nFn)modm 表示 Fibonacci 数列前 n 项变形后的和 modm 的值。
现在佳佳告诉你了一个 nm,请求出 T(n) 的值。

思路

Sn=i=1nfi

Wn=i=1nfi×(ni)

由 :

Tn=i=1nfi×i

可得:

Tn=Sn×nWn

Wn=i=1nfi×(ni) 可得:

Wn=i=1n1Sn

故可以用矩阵快速幂算出 SnWn

列出矩阵:

[1,1,0,01,0,0,01,0,1,00,0,1,1]×[FnFn1Sn1Wn1]=[Fn+1FnSnWn]

总结

这是一道挺好的矩阵快速幂的题,既有思维含量,又有算法含量。

首先思维方面,这题可以巧妙的转化 Tn,把一个难求的值变成两个易求的值相减。

另一方面,矩阵快速幂也调了我很久,一个 n\timem 的矩阵和一个 m×q 的矩阵相乘,三层循环分别是 n,q,m,注意顺序。

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, m, i, j, k;
int a[5][5]= {
	{0,0,0,0,0},
	{0,1,1,0,0},
	{0,1,0,0,0},
	{0,1,0,1,0},
	{0,0,0,1,1}
};
int ans[5][5], mo;
void cheng(int a[5][5], int b[5][5], int n, int m, int q) {
	int c[5][5]= {0}, i, j, k;
	for(i=1; i<=n; ++i)
		for(j=1; j<=q; ++j)
			for(k=1; k<=m; ++k)
				c[i][j]=(c[i][j]+a[i][k]*b[k][j])%mo;
	memset(a, 0, sizeof(c));
	memcpy(a, c, sizeof(c));
}
signed main() {
	scanf("%lld%lld", &n, &mo); m=n;
	ans[1][1]=ans[2][2]=ans[3][3]=ans[4][4]=1;
	while(n) {
		if(n&1) cheng(ans, a, 4, 4, 4);
		n>>=1; cheng(a, a, 4, 4, 4);
	}
	memset(a, 0, sizeof(a)); a[1][1]=1;
	cheng(ans, a, 4, 4, 1);
	printf("%lld", ((ans[3][1]*m-ans[4][1])%mo+mo)%mo);
	return 0;
}

posted @   zhangtingxi  阅读(345)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示