题目链接
题目描述
从 颗石子开始,每次操作可以选择将当前的
颗石子摆成
的矩形(其中
),然后保留其中一行的
颗石子,其余丢弃。游戏在剩下 1 颗石子时结束。游戏得分是每轮操作前所拥有的石子数之和。求最优策略下的最大得分。
解题思路
本题要求一个最大得分,这是一个典型的最优化问题,我们可以尝试用动态规划的思路来分析。
设 表示从
颗石子开始游戏能获得的最大得分。
根据题意,游戏在剩下 1 颗石子时结束,所以
。
对于
的情况,一次操作将石子数从
变为
,其中
是
的一个真因子(
)。得分会增加
,之后的游戏得分则取决于从
开始能获得的最大分数
。
为了使总分最大,我们应该选择一个能使后续得分
最大的真因子
。因此,我们可以写出状态转移方程:
接下来我们分析 函数的性质。
是一个严格单调递增的函数。也就是说,如果
,那么
。
这是因为
至少等于
,所以
保证了
的首项就大于
的首项,后续的累加项也遵循这个规律,因此总和也更大。
既然 随着
的增大而增大,那么为了让
最大,我们应该选择最大的那个真因子
。
一个数
的最大真因子可以通过用
除以它的最小质因子得到。例如,
的最小质因子是
,其最大真因子就是
。
的最小质因子是
,其最大真因子是
。
因此,最优策略在每一步都是确定的:从当前的石子数 变成它的最大真因子。
算法流程如下:
- 初始化总得分
score
为 0,当前石子数current_n
为。
- 进入一个循环,只要
current_n
大于 0: a. 将current_n
加入到score
中。 b. 如果current_n
等于 1,游戏结束,跳出循环。 c. 找到current_n
的最小质因子。 d. 更新
current_n
为它的最大真因子,即current_n / p
。 - 返回
score
。
寻找最小质因子可以通过试除法实现:从 2 开始向上遍历,第一个能整除 current_n
的数就是它的最小质因子。
代码
#include <iostream>
using namespace std;
// 查找n的最小质因子
long long find_smallest_prime_factor(long long n) {
if (n % 2 == 0) {
return 2;
}
for (long long i = 3; i * i <= n; i += 2) {
if (n % i == 0) {
return i;
}
}
// 如果没有找到小于等于其平方根的因子,说明n本身是质数
return n;
}
int main() {
long long n;
cin >> n;
long long score = 0;
while (n > 0) {
score += n;
if (n == 1) {
break;
}
long long p = find_smallest_prime_factor(n);
n /= p;
}
cout << score << "\n";
return 0;
}
import java.util.Scanner;
public class Main {
// 查找n的最小质因子
public static long findSmallestPrimeFactor(long n) {
if (n % 2 == 0) {
return 2;
}
for (long i = 3; i * i <= n; i += 2) {
if (n % i == 0) {
return i;
}
}
// 如果没有找到小于等于其平方根的因子,说明n本身是质数
return n;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong();
long score = 0;
while (n > 0) {
score += n;
if (n == 1) {
break;
}
long p = findSmallestPrimeFactor(n);
n /= p;
}
System.out.println(score);
}
}
def find_smallest_prime_factor(n):
"""查找n的最小质因子"""
if n % 2 == 0:
return 2
i = 3
while i * i <= n:
if n % i == 0:
return i
i += 2
# 如果没有找到小于等于其平方根的因子,说明n本身是质数
return n
n = int(input())
score = 0
while n > 0:
score += n
if n == 1:
break
p = find_smallest_prime_factor(n)
n //= p
print(score)
算法及复杂度
- 算法:贪心算法 + 试除法
- 时间复杂度:
。游戏进行的步数是
的质因子个数,为
级别。每一步都需要寻找最小质因子,这需要
的时间,其中
是当前步的石子数。整个过程的总时间由第一步寻找最小质因子的时间决定,即
。
- 空间复杂度:
,只需要常数个变量。