当前位置:首页 > GESP > 【GESP五级真题】挑战怪物(洛谷B4050)题解:质数筛法+动态规划优化,高效攻克魔法攻击策略

【GESP五级真题】挑战怪物(洛谷B4050)题解:质数筛法+动态规划优化,高效攻克魔法攻击策略

2天前

【GESP五级真题】挑战怪物(洛谷B4050)题解:质数筛法+动态规划优化,高效攻克魔法攻击策略 GESP五级考试 洛谷B4050 质数筛法 动态规划 算法优化 第1张

一、题目解读

2024年GESP五级题“挑战怪物(洛谷B4050)”要求玩家计算击败怪物所需的最小攻击次数。怪物血量H可被分解为魔法攻击(消耗质数血量)与物理攻击(每次固定伤害)的组合。题目难点在于如何高效枚举质数与物理攻击的搭配,找到最优解。需结合数学逻辑与算法优化,避免暴力枚举导致的超时。

二、解题思路

1. 质数预处理:采用埃拉托斯特尼筛法生成质数表,减少运行时的质数检测开销。

2. 纯物理攻击判定:通过二进制递增加法(1 << cnt)快速检查是否能用纯物理攻击解决(即血量为2的幂次方)。

3. 魔法+物理组合优化:遍历质数表,用当前质数减少怪物血量,递归检查剩余血量是否可纯物理解决。若可行,则记录魔法+物理的总次数,更新最小攻击数。

4. 动态规划思想:通过预处理与递推,避免重复计算,确保时间复杂度可控。

三、解题步骤

1. 输入处理:读取测试用例数量T及每个血量H,记录最大血量max_h用于质数表范围。

2. 质数预处理:调用sieve(max_h)生成primes表,存储所有不超过max_h的质数。

3. 主循环求解:

    对每个h,先调用check_physical(h)判断纯物理攻击次数。

    若纯物理可行,记录次数;否则遍历质数表,计算h - p的纯物理次数,若存在则更新最小次数。

4. 输出结果:按测试用例顺序输出最小攻击次数。

四、代码与注释

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

vector<int> primes; // 预计算质数表

// 埃拉托斯特尼筛法预处理质数
void sieve(int max_h) {
    vector<bool> is_prime(max_h + 1, true);
    is_prime[0] = is_prime[1] = false; // 0和1非质数
    for (int i = 2; i <= max_h; ++i) {
        if (is_prime[i]) { // 若i是质数
            primes.push_back(i); // 加入质数表
            for (int j = i * 2; j <= max_h; j += i) {
                is_prime[j] = false; // 标记i的倍数
            }
        }
    }
}

// 检查是否能用纯物理攻击击败
int check_physical(int h) {
    int sum = 0, cnt = 0; // 累计伤害与次数
    while (sum < h) {
        sum += (1 << cnt); // 每次伤害为2的cnt次方
        cnt++;
    }
    return (sum == h)? cnt : -1; // 若刚好达到血量,返回次数;否则-1
}

// 主处理函数
int solve(int h) {
    int min_attacks = check_physical(h); // 优先检查纯物理方案

    // 尝试所有可能的魔法攻击组合
    for (int p : primes) {
        if (p > h) break; // 质数超过血量时终止遍历
        int remaining = h - p; // 剩余血量
        if (remaining < 0) continue; // 若魔法攻击溢出,跳过
        
        int physical_attacks = check_physical(remaining);
        if (physical_attacks!= -1) { // 若剩余血量可纯物理解决
            int total = 1 + physical_attacks; // 1次魔法 + 物理次数
            if (min_attacks == -1 || total < min_attacks) {
                min_attacks = total; // 更新最小次数
            }
        }
    }
    return min_attacks;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); // 加快IO速度

    int t, max_h = 0;
    cin >> t; // 读取测试用例数量
    vector<int> test_cases(t);
    
    // 读取所有测试用例并找出最大值
    for (int i = 0; i < t; ++i) {
        cin >> test_cases[i];
        if (test_cases[i] > max_h) {
            max_h = test_cases[i];
        }
    }
    
    sieve(max_h); // 预处理质数表

    for (int h : test_cases) {
        cout << solve(h) << "\n"; // 输出每个测试用例的结果
    }
    
    return 0;
}

五、总结

本题巧妙结合质数特性和动态规划思维,通过预处理质数表规避重复计算,大幅降低时间复杂度。代码中“纯物理攻击判定”利用二进制特性简化判断,而“魔法攻击枚举”则通过质数筛选优化搜索空间。此类算法设计需平衡数学逻辑与编程实现,对竞赛选手的优化意识与代码效率要求较高。掌握埃拉托斯特尼筛法及动态规划思想,可为同类问题提供通用解法。



原创内容 转载请注明出处

分享给朋友:

相关文章

70.爬楼梯|三步破解动态规划核心奥秘

70.爬楼梯|三步破解动态规划核心奥秘

题意新解:站在楼梯底仰望n级台阶,每步可选1或2阶,最终的路径组合犹如斐波那契数列般展开。比如到达第3阶的路径可由第1阶跨两步,或第2阶跨一步构成,这种递推规律揭示了两两相邻状态间的紧密关联。思路解析...

IOI 1994 洛谷1216:如何用O(1)空间解决数字三角形问题?附代码实现

IOI 1994 洛谷1216:如何用O(1)空间解决数字三角形问题?附代码实现

题目重解:数字三角形是一个经典的动态规划问题,给定一个由数字组成的三角形结构,从顶部出发,每次可以移动到下方相邻的数字,最终到达底部。我们需要找到一条路径,使得路径上经过的数字总和最大。这个问题可以很...

从零到一掌握背包问题:洛谷P1164题解精讲,附带优化

从零到一掌握背包问题:洛谷P1164题解精讲,附带优化

题目重解:小A带着m元钱来到餐馆,菜单上有n道菜,每道菜都有确定的价格。现在需要计算出刚好花完m元的点菜方案总数。这个问题看似简单,但当菜品数量增多时,暴力枚举就会变得不可行,需要更高效的算法来解决。...

GESP2023年六级真题解析:动态规划解决小杨买饮料问题(洛谷3873)

GESP2023年六级真题解析:动态规划解决小杨买饮料问题(洛谷3873)

一、题目解读小杨买饮料是GESP 2023年六级认证考试中的一道经典动态规划题目,考察学生对背包问题的理解和应用能力。题目描述小杨需要购买n种饮料,每种饮料有特定的体积w和价格v,他要在不超过容量l的...

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

一、题目解读2019年CSP-J的“纪念品”问题(对应洛谷P5662)要求玩家在T天内通过买卖纪念品最大化金币收益。每天可交易N种商品,需计算最优策略下的最终金币数。题目强调动态规划思维与资源分配优化...

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

一、题目解读题目要求在一个n×m的网格中,从左上角到右下角选择一条路径,路径上的数字可重复取用,求取数之和的最大值。路径限制为仅能向右或向下移动。需注意路径的灵活性与重复取数的可能性,传统单向动态规划...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。