方法不太好想,参考别人的;
i=0 | i%a | i%b | abs(i%a-i%b) |
0 | 0 | 0 | 0 |
1 | 1 | 1 | 0 |
2 | 2 | 2 | 0 |
3 | 0 | 3 | 3 |
4 | 1 | 4 | 3 |
5 | 2 | 0 | 2 |
6 | 0 | 1 | 1 |
7 | 1 | 2 | 1 |
8 | 2 | 3 | 1 |
……
当i%a,i%b都是递增时,他们的值都是一样的;
所以只要求出每个序列的长度,然后再乘上第一项的值就可以得到这段序列的值,序列的长度很好算,即是min(a-i%a,b-i%b)。如看上例中i为6,7,8时,i%a为0,1,2;i%b是1,2,3;7是在6的基础上都加了1,8也一样,所以7和8的abs(i%a-i%b)肯定和6是一样的。长度当然为min(3-0,5-1);也可以理解为看这个序列能上升到的最高高度。
#include"stdio.h"
#include"string.h"
#include"math.h"
__int64 min(__int64 a,__int64 b)
{
return a>b?b:a;
}
__int64 fun(__int64 a,__int64 b)//求出最大公约数;
{
return !b?1:fun(b,a%b);
}
__int64 fun1(__int64 a,__int64 b)//求出最小公约数;
{
return a/fun(a,b)*b;
}
__int64 find(__int64 n,__int64 a,__int64 b)
{
__int64 i,temp;
__int64 sum=0;
for(i=0;i<n;)
{
temp=min(a-i%a,b-i%b);
if(i+temp>=n)
temp=n-i;
sum+=abs(i%a-i%b)*temp;
i=i+temp;
}
return sum;
}
int main()
{
__int64 k,h,a,b;
__int64 n,sum;
scanf("%I64d",&k);
while(k--)
{
scanf("%I64d%I64d%I64d",&n,&a,&b);
h=fun1(a,b);
if(n<=h)
sum=find(n,a,b);
else
{
sum=n/h*find(h,a,b)+find(n%h,a,b);//以最小公倍数为周期;
}
printf("%I64d\n",sum);
}
return 0;
}