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;
    }
    
    
  • 相关阅读:
    20120110 自己写的基于jquery的翻页效果
    搜来的 可爱的if ie
    哎~~~纠结死了的终于解决的i6的fixed属性
    2011815发现可好的js繁简转换代码 写这些的人。。好厉害呀 收藏了~~~
    网站制作CSS图片转换滤镜代码(貌似只对ie有用。。。)
    2011811 右下角弹出渐隐的广告代码 可以关闭 可以缩小 还各种兼容(ff opera ie6、7、8都试过了)值得保留哎~~~
    20120604 自己写的基于jquery的类似百度贴吧头像提示效果
    UFT textUtil object 解决奇怪问题
    UFT send request & get response
    UFT connect sql (1)
  • 原文地址:https://www.cnblogs.com/bifanwen/p/12498831.html
Copyright © 2011-2022 走看看