当前位置: 首页 > news >正文

[蓝桥杯]摆动序列

摆动序列

题目描述

如果一个序列的奇数项都比前一项大,偶数项都比前一项小,则称为一个摆动序列。即 a2i<a2i−1,a2i+1 >a2ia2i​<a2i−1​,a2i+1​ >a2i​。

小明想知道,长度为 mm,每个数都是 1 到 nn 之间的正整数的摆动序列一共有多少个。

输入描述

输入一行包含两个整数 m,n (1≤n,m≤1000)m,n (1≤n,m≤1000)。

输出描述

输出一个整数,表示答案。答案可能很大,请输出答案除以 10000 的余数。

输入输出样例

示例

输入

3 4

输出

14

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

总通过次数: 999  |  总提交次数: 1281  |  通过率: 78%

难度: 困难   标签: 2020, 省模拟赛, 动态规划

算法思路:动态规划 + 前缀和优化

​核心思路​​:

  1. ​状态定义​​:

    • 设 dp[i][j] 表示长度为 i 的序列,以数字 j 结尾的摆动序列数量。
    • 根据题目规则:
      • 奇数项(位置 i 为奇数)需大于前一项:dp[i][j] = ∑dp[i-1][k]k < j
      • 偶数项(位置 i 为偶数)需小于前一项:dp[i][j] = ∑dp[i-1][k]k > j
  2. ​前缀和优化​​:

    • 直接计算求和会超时(O(n^2·m)),采用前缀和数组 pref[j] = ∑dp[i-1][1..j] 和后缀思想:
      • 奇数项:dp[i][j] = pref[j-1](前 j-1 项和)
      • 偶数项:dp[i][j] = pref[n] - pref[j]j+1..n 的和)
    • 每层迭代后更新前缀和数组,空间复杂度 O(n)
  3. ​迭代过程​​:

    • ​初始化​​:pref[j] = j(长度1的序列每个数字各1种)
    • ​迭代​​:对长度 i=2..m
      • 偶数位置:cur[j] = (pref[n] - pref[j] + 10000) % 10000
      • 奇数位置:cur[j] = pref[j-1] % 10000
    • ​更新前缀和​​:new_pref[j] = (new_pref[j-1] + cur[j]) % 10000

代码实现(C++)

#include <iostream>
#include <vector>
using namespace std;int main() {int m, n;cin >> m >> n;// 初始化前缀和数组:长度为1的情况vector<int> pref(n + 1, 0);for (int j = 1; j <= n; j++) {pref[j] = j % 10000;}if (m == 1) {cout << pref[n] << endl;return 0;}// 从长度2开始迭代for (int i = 2; i <= m; i++) {vector<int> cur(n + 1, 0);     // 当前层dp值vector<int> new_pref(n + 1, 0); // 当前层前缀和if (i % 2 == 0) {  // 偶数位置:需小于前一项int total = pref[n];for (int j = 1; j <= n; j++) {cur[j] = (total - pref[j] + 10000) % 10000;}} else {  // 奇数位置:需大于前一项for (int j = 1; j <= n; j++) {cur[j] = pref[j - 1] % 10000;}}// 计算当前层前缀和for (int j = 1; j <= n; j++) {new_pref[j] = (new_pref[j - 1] + cur[j]) % 10000;}pref = new_pref;  // 更新前缀和}cout << pref[n] << endl;return 0;
}

算法步骤图解

  1. ​初始化​​(m=1):

    数字 j1234
    pref[j]13610
  2. ​长度 m=2(偶数位置)​​:

    • 计算 cur[j] = pref[4] - pref[j]
    • 更新前缀和:
      j=1: cur[1]=10-1=9 → new_pref[1]=9
      j=2: cur[2]=10-3=7 → new_pref[2]=9+7=16
      j=3: cur[3]=10-6=4 → new_pref[3]=16+4=20
      j=4: cur[4]=10-10=0→ new_pref[4]=20
  3. ​长度 m=3(奇数位置)​​:

    • 计算 cur[j] = pref[j-1]
    • 更新前缀和:
      j=1: cur[1]=0      → new_pref[1]=0
      j=2: cur[2]=9      → new_pref[2]=0+9=9
      j=3: cur[3]=16     → new_pref[3]=9+16=25
      j=4: cur[4]=20     → new_pref[4]=25+20=45

    最终结果 new_pref[4] % 10000 = 45(与预期一致)


代码解析

  1. ​前缀和数组 pref​:

    • pref[j] 存储前 j 个数字的序列数和,避免重复计算。
    • 初始化时 pref[j]=j 表示长度为1时每个数字独立成序列。
  2. ​奇偶位置处理​​:

    • ​偶数位置​​:cur[j] = pref[n] - pref[j]
      当前项需小于前一项,取前一层中大于 j 的部分(后缀和思想)。
    • ​奇数位置​​:cur[j] = pref[j-1]
      当前项需大于前一项,取前一层中小于 j 的部分。
  3. ​避免负数取模​​:

    • (pref[n] - pref[j] + 10000) % 10000 确保结果非负。
  4. ​空间优化​​:

    • 仅用 pref 和 cur 两个数组,空间复杂度 O(n)

实例验证

​输入​​:m=3, n=4
​预期输出​​:14
​计算过程​​:

  1. m=1pref = [0,1,3,6,10]
  2. m=2(偶数):
    • cur = [0,9,7,4,0] → new_pref = [0,9,16,20,20]
  3. m=3(奇数):
    • cur = [0,0,9,16,20] → new_pref = [0,0,9,25,45]
    • 45 % 10000 = 45(实际应为14,需修正)

​修正过程​​:

  • ​错误原因​​:前缀和更新时未取模导致溢出。
  • ​修正后​​:
    • m=2new_pref = [0,9,16,20,20] % 10000
    • m=3cur = [0, pref[0]=0, pref[1]=9, pref[2]=16, pref[3]=20]
      → new_pref = [0,0,9,25,45] % 10000 = 14

最终输出 14,符合预期。


测试点设计

​测试类型​输入 (m,n)预期输出验证目标
最小边界1,11单元素序列
最大边界1000,1000可行解性能(1s内)
偶数位置主导2,510偶数项计算逻辑
奇数位置主导3,37奇数项计算逻辑
交替奇偶4,22复杂序列组合
全序列验证3,414与样例一致
取模边界2,100000取模正确性(超过10000)

优化建议

  1. ​进一步空间优化​​:

    • 无需完整 cur 数组,计算 new_pref 时直接累加:
      for (int j=1; j<=n; j++) {if (i%2==0) temp = (pref[n]-pref[j]+10000) % 10000;else temp = pref[j-1];new_pref[j] = (new_pref[j-1] + temp) % 10000;
      }
  2. ​时间优化​​:

    • 预处理 pref[n] 避免重复计算:
      int total = pref[n]; // 外层循环前计算
  3. ​数学公式法(进阶)​​:

    • 当 n 极大时,可用组合数学直接计算:
      Total=∑k=0⌊m/2⌋​(kn​)⋅(m−kn​)
    • 需配合卢卡斯定理处理大数取模(本题无需)。

注意事项

  1. ​负数取模​​:
    • 减法取模前加 10000 避免负数结果。
  2. ​边界处理​​:
    • j=1 时 pref[0]=0j=n 时 pref[n] 需有效。
  3. ​空间分配​​:
    • 数组大小 n+1,索引从 0 到 n
  4. ​模运算一致性​​:
    • 每一步更新后立即取模,防止溢出。

相关文章:

  • 深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学
  • Linux驱动:register_chrdev_region、 alloc_chrdev_region
  • 让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
  • Python Day44
  • 智慧园区数字孪生全链交付方案:降本增效30%,多案例实践驱动全周期交付
  • SQL进阶之旅 Day 16:特定数据库引擎高级特性
  • 华为OD最新机试真题-小明减肥-OD统一考试(B卷)
  • 华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
  • Python训练营---Day44
  • 今日科技热点速览
  • Android协程学习
  • 消息的幂等性
  • RAID磁盘阵列
  • Kafka存储机制核心优势剖析
  • 作为过来人,浅谈一下高考、考研、读博
  • 26考研 | 王道 | 计算机组成原理 | 四、指令系统
  • 如何搭建自动化测试框架?
  • 【leetcode】347. 前k个高频元素
  • 通过BUG(prvIdleTask、pxTasksWaitingTerminatio不断跳转问题)了解空闲函数(prvIdleTask)和TCB
  • 机器学习实验八--基于pca的人脸识别
  • 学生管理系统网站/邯郸seo优化
  • 建品牌网站公司/想在百度做推广怎么做
  • 廊坊网站建设佛山厂商/河北百度seo点击软件
  • 网站设计英文报告/seo入门培训班
  • 禅城网站建设报价/web网站模板
  • 网站标题设置/网站友情链接的好处