1303. 斐波那契前 n 项和

题目链接

1303. 斐波那契前 n 项和

输入 nm,求 Fibonacci数列的前 n 项和 Snmodm

输入格式

共一行,包含两个整数 nm

输出格式

输出前 n 项和 Snmodm 的值。

数据范围

1n2000000000,
1m1000000010

输入样例:

5 1000

输出样例:

12

解题思路

矩阵乘法,快速幂

构造一个函数 fn=[Fn,Fn+1,sn],寻找 fnfn+1 之间的关系,即 fn+1=fn×A,可得 A=[010111001]
则有 fn=f1×An1,可用快速幂配合矩阵乘法快速求解 fn

  • 时间复杂度:O(33×logn)

推式子

Fn+2=Fn+1+Fn,即 Fn=Fn+2Fn+1,则
{F1=F3F2F2=F4F3F3=F5F4F4=F6F5Fn=Fn+2Fn+1,得 sn=Fn+2F2

  • 时间复杂度:O(22×logn)

快速倍增法
源自 抽风巨佬

这里 fn 为第 n 个 Fibonacci数列
结论: fn=fkfnk+1+fk1fnk(2kn)
证明:

fn=fn1+fn2=f2fn2+1+f1fn2

结论对于 k=2 成立
假设结论对于 k=i 成立
则有 fn=fifni+1+fi1fni
⇒=fi(fni+fni1)+fi1fni
⇒=fifni+fifni1+fi1fni
⇒=(fi+fi1)fni+fifni1
⇒=fi+1fni+fifni1
所以结论对于 k=i+1 成立, 证毕
那么根据结论,当 n=2k 时,有
f2k=fkfk+1+fk1fk=fk(fk+1+fk1)=fk(2fk+1fk)
n=2k+1 时,有
f2k+1=fkfk+fk+1fk+1=fk2+fk+12
也就是说,我们可以通过递归求出 fk2fk2+1 来得到 fk
据此,可以通过快速倍增法通过分奇偶快速求出 fn

  • 时间复杂度:logn

代码

  • 矩阵乘法
// Problem: 斐波那契前 n 项和 // Contest: AcWing // URL: https://www.acwing.com/problem/content/1305/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } int n,m; LL a[3][3]={{0,1,0},{1,1,1},{0,0,1}},f1[3]={1,1,1}; void mulself(LL a[3][3]) { LL c[3][3]={0}; for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<3;k++) c[i][j]=(c[i][j]+a[i][k]*a[k][j])%m; memcpy(a,c,sizeof c); } void mul(LL f1[3],LL a[3][3]) { LL c[3]={0}; for(int i=0;i<3;i++) for(int j=0;j<3;j++) c[i]=(c[i]+f1[j]*a[j][i])%m; memcpy(f1,c,sizeof c); } int main() { cin>>n>>m; n--; while(n) { if(n&1) mul(f1,a); mulself(a); n>>=1; } cout<<f1[2]; return 0; }
  • 推式子
// Problem: 斐波那契前 n 项和 // Contest: AcWing // URL: https://www.acwing.com/problem/content/1305/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } int n,m; LL a[2][2]={{0,1},{1,1}},f1[2]={1,1}; void mulself(LL a[2][2]) { LL c[2][2]={0}; for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) c[i][j]=(c[i][j]+a[i][k]*a[k][j])%m; memcpy(a,c,sizeof c); } void mul(LL f1[2],LL a[2][2]) { LL c[2]={0}; for(int i=0;i<2;i++) for(int j=0;j<2;j++) c[i]=(c[i]+f1[j]*a[j][i])%m; memcpy(f1,c,sizeof c); } int main() { cin>>n>>m; n++; while(n) { if(n&1) mul(f1,a); mulself(a); n>>=1; } cout<<(f1[0]-1+m)%m; return 0; }
  • 快速倍增法
// Problem: 斐波那契前 n 项和 // Contest: AcWing // URL: https://www.acwing.com/problem/content/description/1305/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } int n,m; PLL f(int n) { if(n==1)return {1,1}; PLL t=f(n>>1); LL t1=t.fi,t2=t.se; LL f1=t1*(2*t2%m-t1+m)%m; LL f2=(t1*t1+t2*t2)%m; if(n&1)return {f2,(f1+f2)%m}; return {f1,f2}; } int main() { cin>>n>>m; cout<<(f(n+2).fi-1+m)%m; return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/15904148.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(184)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示