zoukankan      html  css  js  c++  java
  • 洛谷 P1306 斐波那契公约数 题解

    CSDN同步

    原题链接

    前置知识:

    矩阵乘法、斐波那契数列的矩阵公式。

    题意简要:

    (F_i) 表示斐波那契数列的第 (i) 项,求:

    [gcd(F_n,F_m) ]

    我们先考虑 (n > m) .

    首先我们考虑 (gcd) 的两个性质,后面要用:

    [gcd(a,b) = gcd(b,a-b) = gcd(a-k cdot b) ]

    [gcd(a imes b,c) = gcd(a ,c ) imes gcd(b,c) ]

    再考虑 (F) 数列的一个性质:

    [F_{n+1} - F_n = F_{n-1} ]

    下面先求另一个东西:

    [gcd(F_n,F_{n+1}) = gcd(F_n,F_{n+1}-F_n) = gcd(F_{n-1},F_n) = cdots = gcd(F_1,F_2)=1 ]

    得出结论:相邻两个 (F) 的数,其 (gcd)(1).

    可以推论:

    [F_{n+m}=F_{n+m-1}+F_{n+m-2} = 2 imes F_{n+m-2} + F_{n+m-3} = 3 imes F_{n+m-3} +2 imes F_{n+m-4} = cdots = F_{n+1} cdot F_m + F_n cdot F_{m-1} ]

    如果还不懂,可以从上面这个式子进行推论:

    [F_{n+m}=F_2 cdot F_{n+m-1}+F_1 cdot F_{n+m-2} = F_3 cdot imes F_{n+m-2} + F_2 cdot F_{n+m-3} = F_4 cdot F_{n+m-3} +F_3 cdot F_{n+m-4} = cdots = F_{n+1} cdot F_m + F_n cdot F_{m-1} ]

    (因为每次你会发现,(F) 的系数就是 (F)本身!)

    下面可以得出:

    [gcd(F_{n+m},F_n) = gcd(F_{n+1} cdot F_m + F_n cdot F_{m-1} ,F_n) ]

    下面由于 (gcd) 的性质,约去 (F_n) 一项,再拆开做乘法,可得:

    [= gcd(F_{n+1} cdot F_m , F_n) = gcd(F_{n+1},F_n) imes gcd(F_m,F_n) ]

    由上面所说结论 (gcd(F_{n+1},F_n=1)) 可推断:

    [gcd(F_{n+m},F_n) = gcd(F_m,F_n) ]

    由此不断迭代:

    [gcd(F_{n+m},F_n) = gcd(F_m,F_n) = gcd(F_{n-m},F_m) = cdots ]

    你会发现,这其实就是在实施 辗转相减法

    那么,辗转相减法的本质就是在求 (gcd)

    所以可以得出:

    [gcd(F_n,F_m) = F_{gcd(n,m)} ]

    由此,问题简化为:

    (F) 数列的第 (gcd(n,m)) 项。

    显然(如果不会矩阵乘法,或者是矩阵加速等的同学,可以先去学一下),用 矩阵快速幂 可以优雅地解决本题。

    时间复杂度为: (O(log n)). 空间复杂度为: (O(1)).(常数级的矩阵大小不计)

    (这是因为 (gcd(n,m)) 最大为 (n) 当且仅当 (n=m)

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const ll MOD=1e8;
    
    inline ll read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	ll x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    ll n,k;
    
    struct martix {
    	ll a[3][3];
    };  //因为函数不能返回数组,只好写结构体
    martix ans;
    martix a,b;
    
    inline ll gcd(ll n,ll m) {return m?gcd(m,n%m):n;} //gcd迭代
    
    inline martix chengfa(martix x,martix y) {
    	martix ans;
    	for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) ans.a[i][j]=0;
    	for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) for(int k=1;k<=2;k++) {
    		ans.a[i][j]+=x.a[i][k]*y.a[k][j];
    		ans.a[i][j]%=MOD;
    	} return ans;
    } //矩阵乘法
    
    inline martix pw(martix a,ll k) {
    	for(int i=1;i<=2;i++) ans.a[i][i]=1;
    	while(k>0) {
    		if(k&1) ans=chengfa(ans,a);
    		a=chengfa(a,a); k>>=1;
    	} return ans;
    } //矩阵快速幂
    
    int main(){
    	n=read(),k=read();
    	if(n<=2) {printf("1");return 0;}
    	a.a[1][1]=1; a.a[1][2]=1;
    	b.a[1][1]=0; b.a[1][2]=1; b.a[2][1]=1; b.a[2][2]=1;
    	martix t=pw(b,gcd(n,k)-2);
    	ans=chengfa(a,t);
    	printf("%lld
    ",ans.a[1][2]); //得出最终结果
    	return 0;
    }
    
    
  • 相关阅读:
    ElasticSearch 高级DSL查询语句
    docker改国内官方镜像
    step1: python & scrapy安装
    step7: 输出到json文件
    step6: item与pipeline
    step5: 编写spider爬取
    step4: Xpath的使用
    step3: 创建jobbole爬虫
    step2: 爬取廖雪峰博客
    解决WAS更新web.xml文件不生效的问题(web_merged.xml是罪魁祸首)
  • 原文地址:https://www.cnblogs.com/bifanwen/p/12498831.html
Copyright © 2011-2022 走看看