2013 多校第二场 hdu 4611 Balls Rearrangement

来源:互联网 发布:卖家 淘宝国际转运 编辑:程序博客网 时间:2024/06/05 00:49

hdu 4611

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4611

题目大意:题目意思说起来挺烦的,其实就是让你算 ABS(i % a - i % b)的和,i 的范围是 10^9 。

思路:比赛的时候想到最小公倍数了,也想到一段一段来了,可就是不知道哪里脑子抽了,还想整理一下,推出一个公式来。其实,现在反过来想想真心不用,a、b小的时候,根据 LCM 来求,复杂度很小,如果 a、b 大,那么一段一段来很快的。事实证明这样算只需要 15ms 。先开始也WA了几次,是有的地方超 int ,没有强制转化的问题。

貌似也有数学公式,对于不懂数论的我来说,这种做法在效率和思维上已经都可以了,如果有机会的话,再学一下公式吧。。

代码如下:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;typedef __int64 lld;int gcd(int a,int b){    if(a==0 ) return b;    return gcd(b%a,a);}lld cal(int n,int a,int b){    lld  ans =0 ;    for(int i=0;i<n;)    {        int t1 = i%a,t2 = i%b;        int p1 = a-t1,p2 = b-t2;        if(p1<p2)        {            ans += (lld)abs(t1-t2)*p1;            i = i + p1;        }        else        {            ans += (lld)abs(t1-t2)*p2;            i = i + p2;        }        if(i>=n)        {            int h1 = (n-1)%a,h2 = (n-1)%b;            if(p1<p2)                ans -= (lld)abs(t1-t2)*(a-1-h1);            else ans -=(lld)abs(t1-t2)*(b-1-h2);        }    }    //printf("ans = %I64d,n = %d\n",ans,n);    return ans;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        int n,a,b;        scanf("%d%d%d",&n,&a,&b);        if(a>b) swap(a,b);        lld lcm = (lld)a/gcd(a,b)*b;        lld ans=0;        if(lcm<n)        {            ans = cal(lcm,a,b)*(n/lcm)+cal(n%lcm,a,b);        }        else        {            ans = cal(n,a,b);        }        printf("%I64d\n",ans);    }    return 0;}


原创粉丝点击