专题(二)数学与简单DP——AcWing 1205. 买不到的数目

【题目描述】
在这里插入图片描述

AcWing 1205. 买不到的数目

暴力枚举 迭代写法

【思路】
分别枚举m、n的个数
for(m个数)
for(n个数)
k = m * m个数 + n * n个数
O(N^2),只能枚举答案在1000以内的

import java.util.Scanner;
public class Main{
    static int N = 10010;
    static int []f = new int [N];
    public static void main(String args[]){
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt(), m = reader.nextInt();
        for(int i = 0; i < N / m + 1; i ++)//枚举m的个数
            for(int j = 0; j < N / n + 1; j++)//枚举n的个数
            {
                int k = m * i + n * j;
                if( k >= N ) continue;
                f[k] = 1;
            }
        for(int i = N - 1; i >= 0;i --)
            if(f[i] == 0){
                System.out.println(i);
                break;
            }
    }
}


暴力枚举——递归写法

过5/10数据

import java.util.Scanner;
public class Main{
    //判断x能否由m、n组成
    public  static boolean dfs(int x, int m, int n){
        
        if( x < 0) return false;
        
        //x == 0 说明x能由若干m、n组成
        if( x == 0 ) return true;
        
        if( x >= m && dfs(x - m, m, n)) return true;
        if( x >= n && dfs(x - n, m, n)) return true;
        
        return false;
    }
    public static void main(String args[]){
        
        Scanner reader = new Scanner(System.in);
        int m = reader.nextInt(), n = reader.nextInt();
        for(int i = 1000; i >= 1; i --)
        {
            if(!dfs(i, m, n)){
                System.out.println(i);
                break;
            }
        }
        
    }
}

错误写法:

对于有返回值的递归函数,要注意对中间结果的保存和处理,只是把它扔掉了

import java.util.Scanner;
public class Main{
    //判断x能否由m、n组成
    public  static boolean dfs(int x, int m, int n){
        
        if( x < 0) return false;
        
        //x == 0 说明x能由若干m、n组成
        if( x == 0 ) return true;
       
        if( x >= m ) return dfs(x - m, m, n);
        if( x >= n ) return dfs(x - n, m, n);
        
        return false;
    }
    public static void main(String args[]){
        
        Scanner reader = new Scanner(System.in);
        int m = reader.nextInt(), n = reader.nextInt();
        for(int i = 1000; i >= 1; i --)
        {
            if(!dfs(i, m, n)){
                System.out.println(i);
                break;
            }
        }
        
    }
}


AC代码

两个数xy如果互质,那么最大不能组成的数是xy-x-y,如果两个数不互质能组成任何数。这题比较考验数学思维。

引理

给定a,b,如果d =gcd(a, b) >1,那么其凡不是d倍数的a,b都凑不出,因此其凑不出来的数目是INF个。

结论

若a、b均为正整数且gcd(a,b) = 1, 那么 ax + by ,x >= 0, y >= 0,最大不能表示的数为 (a - 1) * (b - 1) = a*b - a - b

import java.util.Scanner;
public class Main{
   
    public static void main(String args[]){
        
        Scanner reader = new Scanner(System.in);
        int a = reader.nextInt(), b = reader.nextInt();
        //公式: (a - 1) * (b - 1) - 1 =ab -a - b
        System.out.println(a * b - a - b);
        
    }
}


包子凑数

在这里插入图片描述

在这里插入图片描述

import java.util.Scanner;
class Main{
    static int N = 110, M = 10000;
    static int a[] = new int [N];
    static boolean f[][] = new boolean[N][M];
    static int gcd(int a, int b){
        if(b == 0) {return a;}
        return gcd(b, a % b);
    }
    public static void main(String args[]){
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt();
        for(int i = 1; i <= n; i ++) {
            a[i] = reader.nextInt();
        }
        int d = 0;
        for(int i = 1; i <= n; i ++){
            d = gcd(d, a[i]);
        }
        if(d != 1) {
            System.out.println("INF");
        }else{
            // 0个物品,重量为0,合法方案
            f[0][0] = true;
            
            for(int i = 1; i <= n; i ++){
                for(int j = 0; j < M; j ++){
                    f[i][j] = f[i - 1][j];
                    for(int k = 0; k * a[i] <= j; k ++){
                        f[i][j] |= f[i - 1][j - k * a[i]];
                    }
                }
            }
            int res = 0;
            for(int j = 1; j < M; j ++){
                if(!f[n][j]){
                    res ++;
                    // System.out.println(j);
                }
            }
            System.out.println(res);
        }
    }
}
import java.util.Scanner;

class Main{
    static int N = 10010;
    static int a[] = new int[110];
    static boolean f[][] = new boolean [110][N];
    public static int gcd(int a, int b){
        if( b == 0) return a;
        return gcd( b, a % b );
    }
    public static void main(String args[]){

        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt();
        for(int i = 1; i <= n; i ++) a[i] = reader.nextInt();
        int d = 0; // 公约数
        
        for(int i = 1; i <= n; i ++)
            d = gcd(a[i], d);  //gcd(2,0) = 2
        if( d != 1) System.out.println("INF");
        else{
            f[0][0] = true;
            for(int i = 1; i <= n; i ++)
                for(int j = 0; j < 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 = 1; i < N; i ++)
                if( ! f[n][i] ) res ++;
            System.out.println(res);
            
            
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值