题解:洛谷 P6065 Sumsets

【题目来源】

洛谷:P6065 [USACO05JAN] Sumsets S - 洛谷

【题目描述】

给出一个整数 \(N\),将 \(N\) 分解为若干个 \(2\) 的次幂的和,共有多少种方法?

【输入】

输入一个整数 \(N\)\(1 \leq N \leq 10^6\))。

【输出】=-

输出方案数对 \(10^9\) 取模的结果。

【输入样例】

7

【输出样例】

6

【核心思想】

  1. 问题分析:给定整数 \(N\),求将 \(N\) 分解为若干个 \(2\) 的次幂之和的方案数(即 \(N = 2^{k_1} + 2^{k_2} + \dots + 2^{k_m}\),允许重复使用相同的 \(2\) 的次幂)。本质是一个受限整数拆分问题,等价于用 \(\{1, 2, 4, 8, \dots\}\) 这些面额的"硬币"凑成金额 \(N\) 的方案数。

  2. 算法选择

    • 递推/动态规划:利用奇偶性分析,发现 \(N\) 的拆分方案数与 \(N-1\)\(N/2\) 存在递推关系,\(O(N)\) 递推求解
  3. 关键步骤

    • 初始化\(\text{dp}[1] = 1\)\(1 = 2^0\),唯一方案),\(\text{dp}[2] = 2\)\(2 = 2^1\)\(2 = 1 + 1\)),\(\text{dp}[3] = 2\)\(\text{dp}[4] = 4\)
    • 递推关系\(i\)\(5\)\(N\)):
      • \(i\) 为奇数\(\text{dp}[i] = \text{dp}[i-1]\)。因为奇数拆分中必然包含至少一个 \(1\)\(2^0\)),去掉这个 \(1\) 后恰好对应 \(i-1\) 的拆分方案,一一对应
      • \(i\) 为偶数\(\text{dp}[i] = \text{dp}[i-1] + \text{dp}[i/2]\)
        • \(\text{dp}[i-1]\):包含至少一个 \(1\) 的拆分方案(去掉一个 \(1\) 对应 \(i-1\) 的拆分)
        • \(\text{dp}[i/2]\):不包含 \(1\) 的拆分方案(所有项都是偶数,除以 \(2\) 后对应 \(i/2\) 的拆分)
    • 取模处理:每次递推后对 \(10^9\) 取模
    • 输出答案\(\text{dp}[N]\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N)\),线性递推
    • 空间复杂度:\(O(N)\),一维 \(\text{dp}\) 数组
  5. 奇偶分类递推的核心思想

    • 奇数的强制含1性:任何奇数的 \(2\) 的次幂拆分必然包含 \(2^0 = 1\)(因为其他项都是偶数,偶数和为偶数,奇数必须加 \(1\)),因此去掉这个 \(1\) 后与 \(i-1\) 的方案一一对应
    • 偶数的二分拆解:偶数 \(i\) 的拆分分为两类——包含 \(1\) 的(对应 \(\text{dp}[i-1]\))和不包含 \(1\) 的(所有项 \(\geq 2\),整体除以 \(2\) 后对应 \(i/2\) 的拆分)
    • 递推而非完全背包:利用奇偶性质将完全背包的 \(O(N \log N)\) 优化到 \(O(N)\),关键在于发现"不含 \(1\) 的偶数拆分"与" \(i/2\) 的任意拆分"之间的缩放对应关系
    • 模数处理:由于 \(N \leq 10^6\),方案数极大,每步取模防止溢出
    • 适用于受限整数拆分、硬币组合、递推关系发现类问题

【解题思路】

【算法标签】

普及 #递推

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int n, dp[1000005]={0, 1, 2, 2, 4};
int main()
{
    cin >> n;  // 输入n
    for (int i=5; i<=n; i++) {  // 遍历5到n,进行递推
        if (i%2==1) {  // 当i为奇数时
            dp[i] = dp[i-1];  // i的方案数与i-1相同
        } else {  // 当i为偶数时
            dp[i] = dp[i/2] + dp[i-1];  // i的方案数为i/2的方案数加上i-1的方案数
        }
        dp[i] %= 1000000000;  // 每计算一次进行一次取模运算
    }
    cout << dp[n] << endl;  // 输出n的方案数
    return 0;
}

【运行结果】

7
6
posted @ 2026-08-29 09:38  团爸讲算法  阅读(11)  评论(0)    收藏  举报