找回密码
 立即注册
查看: 24|回复: 0

2014年蓝桥杯省赛A组波动数列(洛谷P8614):模运算+动态规划

[复制链接]
  • 打卡等级:常驻代表
  • 打卡总天数:33
  • 打卡月天数:2
  • 打卡总奖励:223
  • 最近打卡:2025-08-14 15:12:36

39

主题

1

回帖

4597

积分

VIP会员

积分
4597
发表于 2025-7-25 15:09:56 | 显示全部楼层 |阅读模式
一、算法思路
波动数列是蓝桥杯经典赛题,要求计算满足特定条件的数列数量。本文将详细解析动态规划解法,帮助算法初学者掌握状态设计和转移技巧。
二、完整代码C++

#include <iostream>#include <vector>using namespace std;const int MOD = 100000007;// 自定义取模函数处理负数inline int mod(int x, int n) {    return (x % n + n) % n;}int main() {    int n, s, a, b;    cin >> n >> s >> a >> b;        // dp[j]表示前i项的和模n等于j的方案数    vector<vector<int>> dp(n, vector<int>(n, 0));    dp[0[0 = 1;  // 初始状态:0项和为0有1种方案        for (int i = 1; i < n; i++) {        for (int j = 0; j < n; j++) {            // 状态转移:当前项可以+a或-b            dp[i[j = (dp[i-1[mod(j - a*i, n) + dp[i-1[mod(j + b*i, n)) % MOD;        }    }        // 输出结果:满足s ≡ sum mod n的方案数    cout << dp[n-1[mod(s, n) << endl;    return 0;}三、关键算法解析
  • 问题建模

    • 将数列视为每次选择+a或-b的决策序列
    • 利用模运算缩小状态空间

  • 动态规划设计

    • 状态定义:dp[j]表示前i项和模n等于j的方案数
    • 初始状态:dp[0][0] = 1(空序列和为0)
    • 状态转移:考虑+ai和-bi两种情况

  • 负数处理技巧

    • 自定义mod函数处理负数取模
    • 确保数组索引始终有效

四、常见问题解答
Q:为什么要使用模运算? A:模运算可以大幅缩小状态空间,将无限可能转化为有限状态。
Q:状态转移方程如何理解? A:当前状态值来自两种选择方案数的和:前一步选择+a或前一步选择-b。
Q:如何处理大数问题? A:每一步都取模,防止数值溢出并符合题目要求。
来源:竞赛资料

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表