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

    题目描述

    对于Fibonacci数列:1,1,2,3,5,8,13......大家应该很熟悉吧~~~但是现在有一个很“简单”问题:第n项和第m项的最大公约数是多少?

    Update:加入了一组数据。
    输入格式

    两个正整数n和m。(n,m<=10^9)

    注意:数据很大
    输出格式

    Fn和Fm的最大公约数。

    由于看了大数字就头晕,所以只要输出最后的8位数字就可以了。
    输入输出样例
    输入 #1

    4 7

    输出 #1

    1

    说明/提示

    用递归&递推会超时

    用通项公式也会超时

    题解
    一个结论 GCD(f[n] , f[m]) = f[GCD(n , m)];

    证明
    设 n < m , f[n] = a , f[n+1] = b;
    那么f[m] = f[m-n-1]×a + f[m-n]×b;
    f[m] = f[m-n-1]×f[n] + f[m-n]×f[n+1];
    gcd(f[n] , f[m]) = gcd(f[n] , f[m-n-1] × f[n] + f[m-n] × f[n+1]);
    因为 f[n] | f[m-n-1] × f[n]
    所以 gcd(f[n] , f[m]) = gcd(f[n] , f[m-n] × f[n+1]);
    又因为 gcd(f[n] , f[n+1]) == 1;

    gcd(f[n] , f[n+1]) = gcd(f[n] , f[n] + f[n-1]) = gcd(f[n] , f[n-1]) = gcd(f[n-2] , f[n-1]) = gcd(f[1] , f[2]) = 1;

    所以 gcd(f[n] , f[m]) = gcd(f[n] , f[m-n]) = gcd(f[n] , f[m % n]);
    交换一下 n,m
    就可以看到这个很像求 n,m gcd的过程.

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    const int mod = 1e8;
    inline int read()
    {
        register int x = 0 , f = 0; register char c = getchar();
        while(c < '0' || c > '9') f |= c == '-' , c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
        return f ? -x : x;
    }
    int n , m;
    struct Matrix
    {
    	int a[2][2];
    	Matrix() { memset(a , 0 , sizeof a); }
    	Matrix friend operator * (const Matrix &A , const Matrix &B)
    	{
    		Matrix C;
    		for(int i = 0 ; i < 2 ; ++i) for(int j = 0 ; j < 2 ; ++j) for(int k = 0 ; k < 2 ; ++k) C.a[i][j] = (C.a[i][j] + (long long)A.a[i][k] * B.a[k][j] % mod) % mod;
    		return C;
    	}
    }A , B , Ans;
    int main()
    {
    	n = read(); m = read(); int k = __gcd(n , m);
    	A.a[0][0] = A.a[1][0] = A.a[0][1] = 1;
    	B.a[0][0] = 1; Ans.a[0][0] = Ans.a[1][1] = 1; k--;
    	for( ; k ; k >>= 1 , A = A * A) if(k & 1) Ans = Ans * A;
    	Ans = B * Ans;
    	cout << Ans.a[0][0] << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    【剑指Offer】跳台阶&变态跳台阶
    【剑指Offer】替换空格
    【剑指Offer】二维数组中的查找
    【Leetcode】2. Add Two Numbers 两数相加
    HTML学习笔记(一)HTML的一些概念区别
    C#项目中一些文件类型说明
    数据结构初步归纳(一)概念、线性表以及队列和栈
    线程相关概念
    程序开发方法论
    C#集合类型
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12357956.html
Copyright © 2011-2022 走看看