AcWing 1226. 包子凑数(Java 吃数论性质的题 最大不能凑成的数)
原题链接
中等
作者:
Limited
,
2021-02-12 23:12:05
,
所有人可见
,
阅读 661
要点
- 任意两个数的组合必定是其公约数的倍数(该性质可以拓展到多个数)
- 对于任意两个互质(公约数为1)的数$a$、$b$,最大的、无法凑成的数为$ab-a-b$
- 第1点解决“凑不出的数目无限个”的问题。当几个数的公约数不为1时,因为它们组合成的数必定为公约数的倍数,所以最起码有无限个质数不能被组成。
- 反证法,假设公约数不为1时能组成无限个质数。要组成质数,则根据点1该质数必定是公约数的倍数,而质数的因数仅有1和本身,公约数不为1故只能等于该质数本身。因此若质数A可被组成,则公约数为A;若另一个质数B同样能被组成,则公约数应为B,与前者矛盾。所以当公约数不为1时,能组成的质数仅有1个,假设不成立。
- 第2点解决“上界”的问题,原题$A_i$最大值为100,一百及以内最大的两个互质的数为100和99,其最大不能凑成的数为$100*99-100-99=9701$,故取上界到9701以上即可
步骤
- 先读入所有包子数,存到数组
- 判断所有数的最大公约数是否为1,不为1直接输出“INF”退出
- 按完全背包求解“只考虑前i个数且组成的数恰好为j的选法集合,属性:组合方案总数(或其他可区分‘能否凑成’的属性)”
- 遍历一遍最后的状态,统计不能组成的数字的数量
代码
import java.lang.*;
import java.util.*;
public class Main {
static Scanner scanner = new Scanner(System.in);
static int n;
static int[] a = new int[110];
static int[][] f = new int[110][10010];
static int getGcd(int a, int b) {
int temp = a % b;
return temp == 0 ? b : getGcd(b, temp);
}
public static void main(String[] args) {
n = scanner.nextInt();
for (int i = 1; i <= n; i++) {
a[i] = scanner.nextInt();
}
int temp = a[1];
for (int i = 2; i <= n; i++) {
temp = getGcd(temp, a[i]);
}
if (temp != 1) {
System.out.println("INF");
return;
}
f[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= 10000; j++) {
f[i][j] = f[i - 1][j];
if (j >= a[i]) {
f[i][j] += f[i][j - a[i]];
}
}
}
int ans = 0;
for (int i = 0; i <= 10000; i++) {
if (f[n][i] == 0) {
ans++;
}
}
System.out.println(ans);
}
}