HDU 3880 Lucky Numbers 数学题

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3880

题目大意:要构造一个这样的数的集合,里面的数不大于M,且给定a,b两个互质数,对于任意正整数m,集合里至少有m*a或者m*b存在。问这样的集合最少有多少个数。

题目分析:容易想到大致的思路,因为目标是使集合中的数最少,那么我们应该取a,b中较大的那个数,然后以其倍数构成这个集合,这样集合里的数会比取a的倍数少。然后显然还可以继续精简这个集合,即集合里可能有a,b的公倍数,这样的公倍数会同时负担不止一个m*a或m*b,因此可以继续精简集合。
我们来分析以下实例:a = 2,b = 3,M = 28。
令b = max(a,b),首先构造出不大于M的b的公倍数数组:
{3,6,9,12,15,18,21,24,27}
a,b的最小公倍数是a*b,b>a,于是对于含b*b因子的数x = k * b *b,当m是b的倍数时,x/m = k’*b,数x可以由另一个数去表示。
{3,6,9,12,15,18,21,24,27}
具体对这个例子来说就是,对于9 = 3*3,原本9是作为m = 3时,m*3 =3*3 = 9进入集合的,9可以由更小的6代替,即6 = m*2 = 3*2。
同理18 = m * 3,m = 6.可以由更小m*2 = 6*2 = 12代替。(1)
同理27 = m * 3,m = 9,可以由更小的m*2 = 9*2 = 18代替。
即集合变为:
{3,6,12,15,21,24}
此时我们会发现冲突,18已经由(1)的判断中被排除在集合里了,因此27不能被18代替,27仍保留(重新加回来)。
所以27又加回来:
{3,6,12,15,21,24,27}
a = 2,b = 3,M =28时,ans = 7.
规律就是b^n需要用到b^(n-1)来代替,因此需要保留。这样的交替减去可以替代的数,加上不能被替代的数。
具体实现见代码。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
    ll a,b,c,ans;
    while (~scanf("%I64d %I64d %I64d", &a, &b, &c))
    {
        if (a == b) ans = c / a;
        else
        {
            ans = 0;
            b = max(a,b);
            ll k = 1;
            for (ll i = b; i <= c; i = i * b)
            {
                ans += k * (c/i);
                k = -k;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
点赞