专栏文章

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

P6487题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minvhj6t
此快照首次捕获于
2025/12/02 09:01
3 个月前
此快照最后确认于
2025/12/02 09:01
3 个月前
查看原文
这道题目是一个经典的博弈论问题,需要找出Mirko第一次至少取多少石子才能保证获胜。

问题分析

游戏规则简述:
  • 两位玩家轮流取石子,Mirko先行
  • Mirko第一次可以取任意数量的石子
  • 之后每次取石子的数量必须在1到上一次取的数量的2倍之间
  • 取走最后一颗石子的玩家获胜
我们需要找到Mirko第一次最少取多少石子才能确保胜利,假设双方都采用最优策略。

解题思路

这个问题的关键是发现它与斐波那契数列的紧密联系。通过分析可以发现,当石子数量是某个斐波那契数时,后行者有必胜策略;而当石子数量不是斐波那契数时,先行者有必胜策略。
解法的核心思想是:
  1. 生成所有不超过nn的斐波那契数
  2. 从最大的斐波那契数开始,不断从nn中减去,直到nn变为0
  3. 最后一次减去的斐波那契数就是答案

代码

CPP
#include<bits/stdc++.h>
using namespace std;
int main() 
{
    long long n;
    cin >> n;
    // 生成斐波那契数列,直到超过n
    vector<long long> fib;
    fib.push_back(1);
    fib.push_back(1);
    while(fib.back() < n)
    {
        int size = fib.size();
        fib.push_back(fib[size-1] + fib[size-2]);
    }
    long long ans = n;
    // 不断减去最大可能的斐波那契数
    while(n) 
	 {
        for(int i = fib.size() - 1; i >= 0; i--) 
		{
            if (fib[i] <= n) 
			{
                ans = fib[i];
                n -= fib[i];
                break;
            }
        }
        if (n == 0) break;
        // 移除数列中大于当前n的数
        while(fib.back() > n) 
		{
            fib.pop_back();
        }
    }
    
    cout << ans << endl;
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...