包子凑数
题目描述
小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 NN 种蒸笼,其中第 ii 种蒸笼恰好能放 AiAi 个包子。每种蒸笼都有非常多笼,可以认为是无限笼。
每当有顾客想买 XX 个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有 XX 个包子。比如一共有 3 种蒸笼,分别能放 3、4 和 5 个包子。当顾客想买 11 个包子时,大叔就会选 2 笼 3 个的再加 1 笼 5 个的(也可能选出 1 笼 3 个的再加 2 笼 4 个的)。
当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有 3 种蒸笼,分别能放 4、5 和 6 个包子。而顾客想买 7 个包子时,大叔就凑不出来了。
小明想知道一共有多少种数目是包子大叔凑不出来的。
输入描述
第一行包含一个整数 NN (1≤N≤1001≤N≤100)。
以下 N 行每行包含一个整数 AiAi (1≤Ai≤1001≤Ai≤100)。
输出描述
一个整数代表答案。如果凑不出的数目有无限多个,输出 INF。
输入输出样例
示例 1
输入
2
4
5
输出
6
样例说明
凑不出的数目包括:1, 2, 3, 6, 7, 11。
示例 2
输入
2
4
6
输出
INF
样例说明
所有奇数都凑不出来,所以有无限多个
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
总通过次数: 8165 | 总提交次数: 9840 | 通过率: 83%
难度: 困难 标签: 2017, 裴蜀定理, 省赛, 动态规划
问题分析:包子凑数(裴蜀定理 + 动态规划)
核心算法思路
-
裴蜀定理应用:
- 若所有蒸笼容量 Ai 的最大公约数 g=1,则存在无限多个无法凑出的数(输出
INF
) - 若 g=1,则无法凑出的数是有限的(需动态规划统计)。
- 若所有蒸笼容量 Ai 的最大公约数 g=1,则存在无限多个无法凑出的数(输出
-
动态规划(完全背包):
- 状态定义:
dp[j] = true
表示能凑出 j 个包子。 - 初始化:
dp[0] = true
(0 个包子不需要任何蒸笼) - 状态转移:
for (每种蒸笼容量 a[i]) for (j = a[i]; j <= MAX; j++) dp[j] = dp[j] || dp[j - a[i]];
- 统计结果:遍历
dp[1..MAX]
,计数dp[j] = false
的数量
- 状态定义:
算法步骤
-
计算最大公约数:
- 初始化 g=A0,遍历 g=gcd(g,Ai)。
- 若 g=1,输出
INF
并结束。
-
动态规划求解:
- 设背包容量
MAX = 10000
(因 Ai≤100,最大不可凑数 <1002) - 对每种蒸笼容量更新
dp
数组。
- 设背包容量
-
统计无法凑出的数量:
- 遍历
dp[1..MAX]
,统计false
的个数。
- 遍历
C++ 代码实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// 计算最大公约数
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);
}int main() {const int MAX = 10000; // 背包最大容量int n;cin >> n;vector<int> a(n);vector<bool> dp(MAX + 1, false); // dp数组初始化// 输入并计算最大公约数int g = 0;for (int i = 0; i < n; i++) {cin >> a[i];g = (i == 0) ? a[i] : gcd(g, a[i]);}// 检查最大公约数if (g != 1) {cout << "INF" << endl;return 0;}// 动态规划(完全背包)dp[0] = true; // 初始化:0个包子可凑出for (int i = 0; i < n; i++) {for (int j = a[i]; j <= MAX; j++) {if (dp[j - a[i]]) dp[j] = true; // 状态转移}}// 统计无法凑出的数量int count = 0;for (int i = 1; i <= MAX; i++) {if (!dp[i]) count++;}cout << count << endl;return 0;
}
代码解析
-
最大公约数计算:
- 使用递归实现辗转相除法,时间复杂度 O(log(min(Ai)))
-
动态规划核心:
- 空间优化:使用一维
dp
数组,避免二维空间开销 - 完全背包逻辑:每种蒸笼无限使用,内层循环正序更新(区别于01背包的逆序)
- 空间优化:使用一维
-
边界与效率:
- 背包容量:
MAX=10000
的设定基于裴蜀定理(Ai≤100 时最大不可凑数 <1002) - 时间复杂度:O(N×MAX),满足 N≤100、MAX=104,1秒内可完成
- 背包容量:
示例验证
- 输入
[4, 5]
:- g=gcd(4,5)=1,动态规划后统计得无法凑出 {1,2,3,6,7,11},输出
6
。
- g=gcd(4,5)=1,动态规划后统计得无法凑出 {1,2,3,6,7,11},输出
- 输入
[4, 6]
:- g=gcd(4,6)=2=1,直接输出
INF
- g=gcd(4,6)=2=1,直接输出