题解 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;
}
}

浙公网安备 33010602011771号