P3938 斐波那契 LCA 规律

解题思路

这道题目是关于斐波那契数列和最近公共祖先(LCA)的问题。题目描述了一个兔子繁殖的模型,这个模型遵循斐波那契数列的规律。

关键观察

  1. 斐波那契树结构:兔子的编号和繁殖方式形成了一个类似斐波那契树的结构。每个月的兔子数量遵循斐波那契数列增长。

  2. 祖先关系:在斐波那契树中,任意一个兔子编号可以表示为若干个斐波那契数的和,这类似于斐波那契进制表示。

  3. LCA查找:两个兔子的最近公共祖先可以通过不断将较大的编号减去最大的不超过它的斐波那契数,直到两个编号相等来实现。这与数论中求最大公约数的欧几里得算法类似。

算法分析

  1. 预处理斐波那契数列:预先计算斐波那契数列的前60项,这足以处理题目中可能出现的最大编号。

  2. LCA查找算法:通过不断减去最大的斐波那契数来缩小问题规模,类似于欧几里得算法,时间复杂度为O(log n)。

  3. 效率:对于每个查询,算法都能在极短的时间内完成,因此可以高效处理大量查询。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3 + 10;
ll f[N]; // 斐波那契数列数组
int m;

// 寻找两个兔子编号a和b的最近公共祖先
ll lca(ll a,ll b)
{
    // 当a和b不相等时,持续处理
    while(a != b)
    {
        // 保证a是较大的数
        if(a < b) swap(a,b);
        // 从大到小遍历斐波那契数列
        for(int i = 60; i >= 1; i--)
            if(f[i] < a){ // 找到最大的不超过a的斐波那契数
                a -= f[i]; // 将a减去这个斐波那契数
                break;
            }
    }
    return a; // 当a和b相等时,即为它们的最近公共祖先
}

int main()
{
    cin >> m; // 读取询问次数
    // 初始化斐波那契数列
    f[1] = f[2] = 1;
    for(int i = 3; i <= 60; i++) f[i] = f[i - 1] + f[i - 2];
    
    // 处理每个询问
    while(m--)
    {
        ll a,b;
        scanf("%lld%lld",&a,&b);
        printf("%lld\n",lca(a,b)); // 输出LCA结果
    }
    return 0;
}

 

posted @ 2025-04-29 16:47  CRt0729  阅读(25)  评论(0)    收藏  举报