题目描述
小明几乎每天早晨都会在一家包子铺吃早餐。这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子
每种蒸笼都有非常多笼,可以认为是无限笼。
每当有顾客想买X个包子,卖包子的大叔就会选出若干笼包子来,使得这若干笼中恰好一共有X个包子。
比如一共有3种蒸笼,分别能放3、4和5个包子。当顾客想买11个包子时,大叔就会选2笼3个的再加1笼5个的(也可能选出1笼3个的再加2笼4个的)。
当然有时包子大叔无论如何也凑不出顾客想买的数量。
比如一共有3种蒸笼,分别能放4、5和6个包子。而顾客想买7个包子时,大叔就凑不出来了。
小明想知道一共有多少种数目是包子大叔凑不出来的。
翻译成人话
给出N个正整数,每个整数有无限多个。任取一些整数相加,得到大于等于1的数。问有多少个数得不到。如果得不到的有无限多个,输出“INF”;否则输出得不到的数量。
例如给出4、5,它们组合不能得到的数有6个:1, 2, 3, 6, 7, 11。其他的数都能通过组合得到。
题解
首先,判断是不是INF
先考虑只有两个正整数的时候,答案假如是INF,也即方程 ax + by = c 在c的所有取值下都没有整数解
如果你不知道这个方程什么时候会有整数解,请看这里:设a ,b是整数且gcd (a , b) = d,如果d不能整除c,那么方程ax + by = c没有整数解,反之能整除的话,方程存在无穷多个整数解。
如果d=1,那ax+by就可以得到所有整数。
那么,题目应该只有两种状态,也就是0和INF才对,为什么还有统计个数呢,别急,ax+by确实可以获得所有整数,但是此时想想x,y可以是负整数,而在本题目中,包子显然不能是负数。
假如c比较小,那么方程可能没有正整数解,但是当c很大时,肯定有x、y的非负整数解。这个可以证明:
gcd(a,b)=1时,ax+by=c的通解是:
x=x0+bn
y=y0−an
再加上ax0+by0=c可以得到
by=c−ax0−abn
取x的一个正整数值,此时如果c够大,那么by就是正的,y自然也是正的
统计无法组合得到的个数
按照前面的推论,c足够大时不需要考虑,那只需考虑c在某一范围之内无法组合的数字。
用dp[i]=1表示第i个整数被计算出来了,最后统计没有被算过的dp[i]数量。
for(int i = 1; i <= n; i++) { //dp[i]:第i个整数是否被计算出来
dp[a[i]]= 1;
for(int j = 0; j + a[i] < 10000; j++)
if(dp[j]) {
dp[j + a[i]] = 1;
}
}
最后统计
for(int i = 1; i < 10000; i++)
if(dp[i] == 0) ans++;
完整代码
//newoj User: ln2037
#include<bits/stdc++.h>
using namespace std;
const int maxn = 13000;
int a[maxn];
int dp[maxn]={0};
int main() {
int n;
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
int g = a[1];
for(int i = 2; i <= n; i++) //计算所有数的gcd
g = __gcd(g, a[i]);
if(g != 1) {
cout << "INF";
return 0;
}
for(int i = 1; i <= n; i++) { //dp[i]:第i个整数是否被计算出来
dp[a[i]]= 1;
for(int j = 0; j + a[i] < 10000; j++)
if(dp[j]) {
dp[j + a[i]] = 1;
}
}
int ans = 0;
for(int i = 1; i < 10000; i++)
if(dp[i] == 0) ans++;
cout << ans;
return 0;
}