hdu 4611 (2013多校第二場第1題)lcm+模擬

題目鏈接: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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章