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; }