题解 P6487 [COCI 2010/2011 #4] HRPA

P6487 [COCI 2010/2011 #4] HRPA

Part1 当 \(n\) 是斐波那契数时,先手唯一的必胜策略是一次性取完

考虑其他情况为什么必败:

如果 \(n = 2\) ,可以分解为 \(1, 1\) ,先手拿 \(1\) 个后后手可以拿完,所以先手必败;

如果 \(n > 2\) ,可以分解为斐波那契的相邻两项 \(fib_{i - 1}, fib_{i}\) ,根据斐波那契数列的性质,如果先手取完 \(fib_{i - 1}\)\(fib_{i} \leq fib_{i - 1} \times 2\) ,所以后手可以直接取完,先手必败;对于如何取 \(fib_{i - 1}\) ,显然它也可以细分为两项相邻的斐波那契数,因此会重复上面的过程,直到分解成 \({1, 1}\)

Part2 Zeckendorf定理:任何正整数都可以表示为若干个不相邻的斐波那契数之和

\(n\) 不为斐波那契数时,它就被分解成了若干个不相邻的斐波那契数,根据上面的分析,对于每个斐波那契数,每次一定要先把它取完,由于不相邻,所以从小到大排列分解出来的斐波那契数,前一项的两倍一定小于后一项。所以必胜策略就是一次取完每一项,最优答案就是第一次取最小的那个斐波那契数。

因此将 \(n\) 分解为若干个斐波那契数之后输出最小的那个就可以了。

代码

void solve(void) {
    i64 n;
    std::cin >> n;
    i64 a, b, c;
    while(n) {
        if(n == 1 || n == 2) {
            std::cout << n;
            return;
        }
        a = 1, b = 2, c = 3;
        while(c < n) a = b, b = c, c = a + b;
        if(c == n) {
            std::cout << n;
            return;
        }
        n -= b;
    }
}
posted @ 2025-10-30 16:20  dbywsc  阅读(4)  评论(0)    收藏  举报