还是历练不够啊,在比赛时一直超时!!
/****************************************************
在多校的时候一直超时,当时找到了循环节为最小公倍数,
但是在求和的时候方法不对,还是没有优化好,导致一直超时
传送门: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;
}