1226. 包子凑数
题目链接
1226. 包子凑数
给出 \(N\) 个数 \(A_i\),求有多少个数不能通过这些数凑出
输入格式
第一行包含一个整数 \(N\)。
接下来 \(N\) 行,每行包含一个整数 \(A_i\)。
输出格式
输出一个整数代表答案。
如果凑不出的数目有无限多个,输出INF。
数据范围
\(1≤N≤100,\)
\(1≤A_i≤100\)
输入样例1:
2
4
5
输出样例1:
6
输入样例2:
2
4
6
输出样例2:
INF
样例解释
对于样例1,凑不出的数目包括:\(1, 2, 3, 6, 7, 11\)。
对于样例2,所有奇数都凑不出来,所以有无限多个。
解题思路
数论,完全背包变形
结论:对于两个互斥的数 \(a,b\),其不能凑出的最大的数为 \((a-1)\times (b-1)-1\)
\(99\) 和 \(98\) 是 \(100\) 内最大的互斥的两个数可以考虑最大的数取 \(10000\),由于再有更多的数的话可选择的数更多,最大的数可能还不止\(10000\),同时,如果 \(n\) 个的数的最大公约数不为 \(1\),则其凑不出来的数有无限个,因为这些数可以约数不为该最大公约数
\(\color{red}{如果 n 中不存在两个互斥的数呢?}\),在 \(100\) 范围内这样的情况很难出现,且题目应该是保证有解的,所以这种情况可以忽略
下面的问题就变成了完全背包问题:
-
状态表示:\(f[i][j]\) 表示前 \(i\) 个数是否可以凑出 \(j\)
-
状态计算:\(f[i][j]=f[i-1][j]\,||\,f[i][j-a[i]]\)
-
时间复杂度:\(O(10000\times n)\)
代码
// Problem: 包子凑数
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1228/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=105;
int n,a[N];
bool f[N][N*N];
int main()
{
cin>>n;
int d=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
d=__gcd(d,a[i]);
}
if(d!=1)puts("INF");
else
{
f[0][0]=true;
for(int i=1;i<=n;i++)
for(int j=0;j<N*N;j++)
{
f[i][j]|=f[i-1][j];
if(j>=a[i])f[i][j]|=f[i][j-a[i]];
}
int res=0;
for(int i=0;i<N*N;i++)res+=!f[n][i];
cout<<res;
}
return 0;
}

浙公网安备 33010602011771号