『藍橋杯』2017省賽 包子湊數——數學篩法 DP

『題目描述』

問題描述

  小明幾乎每天早晨都會在一家包子鋪喫早餐。他發現這家包子鋪有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 <= N <= 100)
  以下N行每行包含一個整數Ai。(1 <= Ai <= 100)

輸出格式

  一個整數代表答案。如果湊不出的數目有無限多個,輸出INF。

樣例輸入

2
4
5

樣例輸出

6

樣例輸入

2
4
6

樣例輸出

INF

樣例說明

  對於樣例1,湊不出的數目包括:1, 2, 3, 6, 7, 11。
  對於樣例2,所有奇數都湊不出來,所以有無限多個。

『解題思路』

  1. 首先解決無窮情況,如果是無窮那麼就是隻有一部分數的倍數覆蓋到了,還有一些沒有覆蓋,所以如果 g=gcd{a[i]},i=1,2,3...g= gcd\{a[i]\},i=1,2,3...不是 11 ,那麼這些數就只覆蓋了所有 gg 的倍數,就一定有某個數的倍數是覆蓋不到的。
  2. 使用類似於線性篩法的思路來把所有可以組合成的數篩掉,篩數首先要設置一個上限,要用到一個結論:對於互質的兩個數p,q,px+py 不能表示的最大數爲p*q-p-q.證明鏈接)p、q的最大值都是100,那麼上限可以確定爲1e4
  3. 考慮篩法的設置:如果一個數 xx 是可以被組合成的,那麼xa[i]x-a[i]必定也是可以組合成的,用一個dp的思想,就可把所有的數篩出來,其初始情況應該是 0,(可以認爲是用0個a[i]a[i]組成的)。許多人是用完全揹包來寫的,但此題中完全揹包的中心思想就是道理。
/*****************************
*author:ccf
*source:POJ-
*topic:
*******************************/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#define ll long long
using namespace std;

const int N = 107,LIM = 1e4;
int n,m,cas;
int a[N];
bool bk[N*N];
ll gcd(ll a,ll b){
	return b ? gcd(b,a%b) : a;
}
int main(){
	//freopen("data.in","r",stdin);
	scanf("%d",&n);
	for(int i = 1; i <= n; ++i) scanf("%d",a+i);
	int g = a[1];
	for(int i  =2; i <= n; ++i) g = gcd(a[i],g);
	if(g != 1){
		printf("INF\n");
		return 0;
	}
	bk[0] = 1;
	for(int i = 1; i <= n; ++i){
		for(int j = a[i]; j < LIM; j++){
			bk[j] = max(bk[j],bk[j-a[i]]);
		}
	}
	int ans = 0;
	for(int i = 1; i < LIM; ++i) 
		if(!bk[i]) ans++;
	printf("%d\n",ans);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章