hdu(4710) Balls Rearrangement

来源:互联网 发布:apache cxf 配置文件 编辑:程序博客网 时间:2024/06/04 19:58

方法不太好想,参考别人的;

不难发现a和b的最小公倍数是个周期。举个例子可以看看:
a=3,b=5
i=0  i%a  i%b  abs(i%a-i%b)

 i=0i%a i%b abs(i%a-i%b) 0 0 0 0 1 1 1 0 2 2 2 0 3 0 3 3 41 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;
}
  

 

原创粉丝点击