You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否用动态规划求解长度为n的子序列模m和≥x的计数问题?

问题解法与DP可行性分析

核心解法:折半搜索(Meet-in-the-Middle)

由于n的范围是1≤n≤42,直接枚举所有242个子序列显然不现实,但将数组拆分为两个大小相近的子集(比如21+21)后,每个子集的子序列数量仅为221=2097152,完全可以处理。具体步骤如下:

  1. 拆分原数组
    将n个元素分成左右两部分,例如左半部分取前k个元素(k=min(21, n)),右半部分取剩余n-k个元素。

  2. 枚举子序列和模m的结果

    • 对左半部分,枚举所有可能的子序列,计算每个子序列的和对m取模的值,将结果存入数组A,然后对A排序。
    • 对右半部分执行同样操作,得到排序后的数组B。
  3. 统计符合条件的组合数
    总共有len(A)*len(B)个子序列组合(包含空序列)。我们需要统计其中满足(a + b) mod m ≥ x的组合数,可以通过计算补集(即(a + b) mod m < x的数量),再用总数减去补集数量得到答案。

    对于每个a ∈ A,利用B的有序性,通过二分查找快速计算符合条件的b的数量:

    • 分两种情况分析(a + b) mod m < x的b的范围:
      1. 当a + b < m时,要求b < x - a,且b ≥ 0,对应区间[0, max(-1, x - a - 1)]。
      2. 当a + b ≥ m时,要求b < x + m - a,且b < m,对应区间[m - a, min(m - 1, x + m - a - 1)]。
    • 对每个有效区间,用二分查找找到B中落在区间内的元素个数,累加得到当前a对应的补集数量。

    最终答案 = 总组合数 - 所有a对应的补集数量之和。如果题目要求子序列非空,需额外判断空序列是否符合条件(空序列和为0,若0≥x则减1)。

动态规划的可行性分析

常规动态规划思路不可行:
如果定义dp[i][j]表示前i个元素中选若干个,和模m等于j的子序列数量,状态空间大小为n*m。由于m可达到10^9,这个规模无论是内存存储还是计算时间都完全无法承受。

折半后的小规模DP可选:
对于拆分后的每个子集(最多21个元素),可以用小规模DP统计子序列和模m的结果:

  • 初始化dp字典或数组,dp[0] = 1(代表空序列)。
  • 对每个元素num,更新dp:新的状态(j + num) mod m的数量加上原dp[j]的值,同时保留原状态(不选当前元素)。
    不过对于21个元素,直接枚举所有子序列并计算模m结果,实现起来比DP更简单直接,效率也相近。

内容的提问来源于stack exchange,提问作者user13313695

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 13:01:13