题目传送门: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;
}