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