問題描述
小明幾乎天天早晨都會在一家包子鋪吃早餐。他發現這家包子鋪有N種蒸籠,其中第i種蒸籠剛好能放Ai個包子。每種蒸籠都有很是多籠,能夠認爲是無限籠。
每當有顧客想買X個包子,賣包子的大叔就會迅速選出若干籠包子來,使得這若干籠中剛好一共有X個包子。好比一共有3種蒸籠,分別能放三、4和5個包子。當顧客想買11個包子時,大叔就會選2籠3個的再加1籠5個的(也可能選出1籠3個的再加2籠4個的)。
固然有時包子大叔不管如何也湊不出顧客想買的數量。好比一共有3種蒸籠,分別能放四、5和6個包子。而顧客想買7個包子時,大叔就湊不出來了。
小明想知道一共有多少種數目是包子大叔湊不出來的。
輸入格式
第一行包含一個整數N。(1 <= N <= 100)
如下N行每行包含一個整數Ai。(1 <= Ai <= 100)
輸出格式
一個整數表明答案。若是湊不出的數目有無限多個,輸出INF。
樣例輸入
2
45
5
樣例輸出
6
樣例輸入
2
4
6
樣例輸出
INF
樣例說明
對於樣例1,湊不出的數目包括:1, 2, 3, 6, 7, 11。
對於樣例2,全部奇數都湊不出來,因此有無限多個。
解題思路:咱們首先觀察第一個樣例
×表示不能湊出,√表示能湊出。觀察到8√能夠從4√+4獲得,10√能夠從5√獲得。
因此咱們得出判斷一個包子數是否能湊出的一個方法:dp解決。設dp[ j ]表示包子數爲j是否能湊出。
有 dp[ j ] |= dp[ j - A[ k ] ] ( k>0 && j - A[k] >=0 )
進一步觀察能夠知道,當連續√的數目>=4時,以後的數目都必定能湊出,由於只要在以前√的基礎上加上最小包子數4便可。
接着觀察第二個樣例: 4 6 最後樣例輸出是INF。這裏能夠證實只有當給出的包子數至少有兩個互質時最終結果不是INF。
反證法:假設n個包子數都不互質,則它們的最小公約數k>1,則它們能夠表示爲
ka1,ka2,ka3, .... kan,則相加結果爲 k( c1*a1 + c2 * a2 + ... + cn*an ) , 那麼當要湊出的數不是k的倍數的時候,必定湊不出。
而不是k倍數的包子數有INF個.
- 要判斷兩個數是否互質,則要計算兩個數的最大公約數是否爲1,用到了展轉相除法,附上大佬詳細證實 https://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html
- 而這裏dp數組的大小與兩個數最大不能組合的數有關.m,n(前提爲互質)最大不能組合的數能夠證實是 m*n - m -n 有興趣的朋友能夠看https://www.cnblogs.com/DestinHistoire/p/10632970.html
根據上面思路寫的代碼提交錯了一題,輸入96,75,100按照思路結果應該是INF,但仔細想一想html
ka1 + ka2 + ka3 +...+ ka4 = gcd( a1,a2,...,an) 的倍數,因此只須要全部包子數的公約數>1便可。(數組
)spa
實現代碼:code
#include<cstdio>
#include<algorithm>
using namespace std;
const int Max_N = 100;
const int Max_K = 10000;//最大不能組合的數不會超過100*100
//輸入
int N;
int A[Max_N];
bool dp[Max_K+1];//dp[] 全局變量初值爲false 固然最好使用前初始化
//展轉相除法
int gcd(int a,int b)
{
return a%b==0 ? b : gcd(b,a%b);
}
void solve()
{
//先判斷是否爲INF
int k = A[0];
for( int i=1; i<N; i++)
{
k = gcd( k, A[i] );//求全部包子數的最大公約數
}
if( k>1 ){
printf("INF\n");
return;
}
sort(A,A+N);
dp[0] = true;
for(int i=1; i<=Max_K; i++)
{
for(int k=0; k<N&&A[k]<=i; k++)
{
if( dp[ i-A[k] ] )
{
dp[i] = true;
break;
}
}
}
int ans=0, cnt = 0;
for(int i=1; i<=Max_K; i++)
{
if( dp[i] )
{
cnt++;
if( cnt==A[0] ) break;//連續√
}
else
{
cnt = 0;
ans++;//不能湊的包子數
}
}
printf("%d\n",ans);
}
int main()
{
scanf("%d",&N);
for(int i=0; i<N; i++)
{
scanf("%d",&A[i]);
}
solve();
return 0;
}