嘘~ 正在从服务器偷取页面 . . .

SP8547 MAIN74 - Euclids algorithm revisited 题解


SP8547 MAIN74 - Euclids algorithm revisited 题解

题目链接:https://www.luogu.com.cn/problem/SP8547

题意

我们经常用大名鼎鼎的欧几里得算法(辗转相除法)来计算两个数的最大公约数。

对于 $(7,3)$,上述代码中的 while 循环将运行两次: $(7,3)\rightarrow(3,1)\rightarrow(1,0)$

现在给你一个整数 $N(0\le N\le10^{18})$,你需要找出和最小的二元组 $(a,b)$ 满足 $(a\ge b\ge0)$ 且上面提到的代码 while 循环将恰好运行 $N$ 次

原文

Consider the famous euclid algoithm to calculate the GCD of two integers $(a, b)$:

int gcd(int a, int b)
{
    while (b != 0)
    {
        int temp = a;
        a = b;
        b = temp % b;
    }
    return a;
}

for input $(7, 3)$ the ‘while’ loop will run $2$ times as follows: $(7, 3) \Rightarrow (3, 1) \Rightarrow (1, 0)$

Now given an integer $N$ you have to find the smallest possible sum of two non-negative integers $a,b (a \ge b)$ such that the while loop in the above mentioned function for $(a, b)$ will run exactly $N$ times.

输入格式

First line of input contains $T (1 \le T \le 50)$ the number of test cases. Each of the following $T$ lines contains an integer $N (0 \le N \le 10^{18})$.

输出格式

For each test case print the required answer modulo $10^9 + 7$ in a seperate line.

这种题不是结论题就是观察题,总之最好的方法就是打个表。

然后你会发现这题跟斐波那契数列有关,那么为什么呢?

首先我们需要一个结论:斐波那契数列的任意相邻两项互质

证明:

诶,很🐮b,这玩意就是这道题的结论。这玩意不打表真的想不到。

时间复杂度 $\mathcal{O}(T\log N)$

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
const int mod = 1e9 + 7;
typedef vector< vector<int> > mat;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
void add(int &x,int y) { (x += y) >= mod ? x -= mod : 0; }
#define N ((int)())

mat mul(mat &A,mat &B)
{
    int n = A.size(), m = A[0].size(), p = B[0].size();
    mat C(n, vector<int>(p));
    for(int k = 0; k < m; k++)
        for(int i = 0; i < n; i++)
            for(int j = 0; j < p; j++)
                add(C[i][j], A[i][k] * B[k][j] % mod);
    return C;
}
mat qpow(mat A, int k)
{
    int n = max(A.size(), A[0].size());
    mat B(n, vector<int>(n));
    for(int i = 0; i < n; i++) B[i][i] = 1;
    for(; k; k >>= 1) {
        if(k & 1) { B = mul(B, A); } A = mul(A,A);
    } return B;
}
void solve()
{
    int n; cin >> n;
    if(n < 2) return cout << 2 * n << '\n', void(0); else { n += 3; }
    mat A(2, vector<int>(2)), B(2, vector<int>(1));
    A[0][0] = A[0][1] = A[1][0] = 1; B[0][0] = B[1][0] = 1;
    A = qpow(A, n - 2); A = mul(A, B); cout << A[0][0] << '\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int Q; cin >> Q; while(Q--) solve();
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/alejan/solution-sp8547


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录