现在的位置: 首页 > 综合 > 正文

2013年多校联合训练2之1001&HDU4611

2013年03月10日 ⁄ 综合 ⁄ 共 1285字 ⁄ 字号 评论关闭

还是历练不够啊,在比赛时一直超时!!

/****************************************************
在多校的时候一直超时,当时找到了循环节为最小公倍数,
但是在求和的时候方法不对,还是没有优化好,导致一直超时

传送门:http://www.cnblogs.com/Rlemon/p/3215491.html


****************************************************/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<climits>
#define maxn 1000005
using namespace std;

long long Gcd(long long a,long long b)//最大公约数
{
    return b==0?a:Gcd(b,a%b);
}
long long Lcm(long long a,long long b)//最小公倍数
{
    return a/Gcd(a,b)*b;
}

int Abs(int x)
{
    return x<0?-x:x;
}

long long n,a,b;
long gcd,lcm;
long long ans;
long long flag1,flag2;

int main()
{
    freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>a>>b;
        if(a>b)swap(a,b);//保证b大于a
        gcd=Gcd(a,b);//初始化
        lcm=Lcm(a,b);
        flag1=0;
        flag2=b;
        ans=0;
        while(flag1<n)
        {
            if(flag1<=flag2&&flag1+a>flag2)//分组思想的体现
            {
                ans+=(long long)((Abs)(flag1%a-flag1%b)*(flag2-flag1))+(long long)((Abs)(flag2%a-flag2%b)*(flag1+a-flag2));
                flag2+=b;
                //cout<<ans<< " ";
            }
            else
            {
                ans+=(long long)((Abs)(flag1%a-flag1%b)*a);
                //cout<<ans<< " ";
            }
            flag1+=a;
            if(flag1==lcm)//判断有多少个循环,有多少个直接累乘
            {
                ans=ans*(n/lcm);
                flag1=n/lcm*lcm;//判断是否还有剩余的数没有加起来
                flag2=flag1+b;
            }
        }
        if(flag1>=n)//多加了的要减去
        {
            for(int i=flag1-1; i>=n; i--)//注意是flag1-1,不是flag1,开始在这儿wa了一次,只是加到了flag1-1
            {
                ans-=Abs(i%a-i%b);
            }
            cout<<ans<<endl;
            continue;
        }
        cout<<ans<<endl;
    }
    return 0;
}

抱歉!评论已关闭.