AcWing 1205. 买不到的数目 题解 (动态规划,数论)

原题链接:AcWing 1205. 买不到的数目 .

题目描述

小明开了一家糖果店。

他别出心裁:把水果糖包成4颗一包和7颗一包的两种。

糖果不能拆包卖。

小朋友来买糖的时候,他就用这两种包装来组合。

当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。

你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。

大于17的任何数字都可以用4和7组合出来。

本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。

输入格式
两个正整数 n,m,表示每种包装中糖的颗数。

输出格式
一个正整数,表示最大不能买到的糖数。

数据范围
2≤n,m≤1000,
保证数据一定有解。

输入样例:

4 7

输出样例:

17

题目分析–动态规划

题目寻找是两个数不能组成的数的最大值。

枚举所有的数,用数组f[i]表示数i是否可以被组合出来
f[i]=true表示i可以被n和m组合出来
当f[i-n]或者f[i-m]可以被表时则f[i]一定可以被表示
于是有状态转移: f[i] = f[i-n]||f[i-m]

什么时候终止呢?
设k = min(n, m),则当存在连续k个数均可以被表示时之后所有的数均可被表示
那么f数组应该开多大呢?
最多循环m*n次若仍然未找到答案则无解。

因为如果枚举到nm还是未找到答案的话,从nm开始又相当于从0开始枚举,进入死循环无解。

C++ 代码实现

#include <iostream>

using namespace std;

const int N = 1e6+10;
bool f[N];

int main() {
    int n, m;
    cin>>n>>m;
    int cnt = 0;//记录连续可组成数的个数
    int k = min(n, m);
    
    f[0] = true;
    int i = 2;
    while(cnt < k) {
        if(i >= n) f[i] = f[i-n];
        if(i >= m) f[i] = f[i] || f[i-m];
        if(f[i]) cnt++;
        else cnt = 0;
        
        i++;
    }
    //到达i已经存在连续k+1个可组成的数了
    cout<<i-k-1<<endl;
    return 0;
}

数论结论

最大数就是 (n-1)*(m-1)-1
证明过程可以参考这里

#include <iostream>

using namespace std;

int main() {
    int n, m;
    cin>>n>>m;
    cout<<(n-1)*(m-1)-1<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/mwl000000/article/details/108214806