題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4611
題意:給你編號爲0~N-1的N個球,先分別放入編號爲0~A-1的盒子中,放球的規則爲 x%A=a%A(x爲球編號,a爲盒子編號),再給你0~B-1個盒子,將A盒子中的求移到B盒子中,移動規則爲 x%B=b%B(x爲球編號,b爲盒子編號),求對於每個球自身放入的A、B盒子編號的差值之和,即 每個球的 |a-b|之和。
思路:由題意可知,每個球更換盒子的週期爲LCM(a,b),即a、b的最小公倍數,而每個週期的差值之和都是固定的,那麼只要對於n小於等於lcm的情況進行計算就可得知所有的差值之和。
代碼:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;
#define LL __int64
LL gcd(LL a,LL b)
{
return b?gcd(b,a%b):a;
}
LL a,b;
LL gao(LL n)
{
LL ans,i,aa,bb,ab;
for(i=ans=aa=bb=ab=0;i<n;)//模擬換盒子的情況
{
ab=min(a-aa,b-bb);
if(i+ab>n)
ab=n-i;
ans+=ab*abs(aa-bb);
aa+=ab;
bb+=ab;
aa%=a;
bb%=b;
i+=ab;
}
return ans;
}
int main()
{
int T;
LL n,lcm,ans,cot;
while(~scanf("%d",&T))
{
while(T--)
{
scanf("%I64d%I64d%I64d",&n,&a,&b);
if(a==b)
{
printf("0\n");
continue;
}
ans=0;
lcm=a/gcd(a,b)*b;
if(lcm<=n)
{
cot=n/lcm;
ans=cot*gao(lcm);
}
ans+=gao(n%lcm);
printf("%I64d\n",ans);
}
}
return 0;
}