蓝桥杯-包子凑数(完全背包+不定方程的数学性质+多个数的最大公因数)

包子凑数

PREV-36

  • 这题首先需要知道不定方程的一些性质,即:ax+by=c的解的情况:
    • 如果a,b互质,则一定有解且由无穷多个。若限制x,y>=0,则ax+by=c有可能有负数解,即存在有限个c使得方程无正数解。且存在max{c|使方程无解的c}=a*b-a-b;
    • 如果a,b不互质,则可能无解。即有<=>无限多个c使方程无解。只有当(c%gcd(a,b)==0)方程才有解。
  • 考虑到本题不止a,b两个系数,有n个系数,所以对于本题,不定方程可以定义为:a0x0+a1x1+a2x2...+anxn=c;
    • 有解<=>a0,a1,..互质。
    • 否则无解,即有无限多个c使得方程无解。
  • 这题的多个系数的不定方程可以转换为完全背包的问题,将系数看成每种物品的重量,c表示背包的重量。x0,x1..表示可以挑选对应物品的数量最多无限个。而且没有价值的限制。
  • 我们采用压缩的方法,使用一维dp替换二维dp,且:dp[j]表示每次输入一个数字a[i],就用前面已经凑出的数字j和现在的数字a[i]相加表示可以凑出来(j+a[i])
  • 每次输入一个新的值,都需要使用以前可以凑出的数加上新输入的数来更新整个dp数组。
/*输入格式
  第一行包含一个整数N。(1 <= N <= 100)
  以下N行每行包含一个整数Ai。(1 <= Ai <= 100)
输出格式
  一个整数代表答案。如果凑不出的数目有无限多个,输出INF。*/
/**
 * 类似于完全背包的模型
 */
package lanQiao;

import java.util.Scanner;

public class 包子凑数 {
	static int n;//1-100
	static int []a=new int[101];
	static int g;//最大公约数
	static boolean []dp=new boolean[10104];//dp[j]表示到了j这个数的时候,该数是否可以被凑出
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner cin=new Scanner(System.in);
		n=cin.nextInt();
		dp[0]=true;
		for(int i=1;i<=n;i++) {
			a[i]=cin.nextInt();
			if(i==1) g=a[i];
			else g=gcd(a[i],g);//求所有数的最大公因数
			for(int j=0;j<10000;j++) {
				if(dp[j]) {//每次输入一个数字a[i],就用前面已经凑出的数字j和现在的数字a[i]相加表示可以凑出来j+a[i]
					dp[j+a[i]]=true;
				}
			}
		}
		if(g!=1) {//这里表示如果所有的a[i]不互质,说明对于某种数,该数可能凑不出来,则存在无数多个凑不出来的数
			System.out.println("INF");
			return;
		}
		//如果互质,说明对于某种数,有解即可以被凑出来
		//统计个数
		int ans=0;
		for(int i=0;i<10000;i++) {
			if(!dp[i])
				ans++;
		}
		System.out.println(ans);
	}
	private static int gcd(int a, int b) {
		// TODO Auto-generated method stub
		if(b==0) return a;
		else return gcd(b,a%b);
	}

}

posted @ 2020-03-15 22:22  Garrett_Wale  阅读(282)  评论(0编辑  收藏  举报