HDU 4611 Balls Rearrangement
令lcm=LCM(a,b),gcd=GCD(a,b)。cal(n,a,b)表示sum(abs(i%a-i%b)),0<=i<n。
显然,答案就是cal(lcm,a,b)*(n/lcm)+cal(n%lcm,a,b)。
cal(n,a,b)可以通过暴力得到,即对i%a和i%b的值分段,连续的一段(遇到0终止)可以直接得到值。
因此,每段的长度将直接影响到时间复杂度。
当lcm较小时,cal中的n不会很大,即使每段长度很小也无所谓。
当lcm较大时,每段的长度会比较大。
1 #include<iostream> 2 #include<algorithm> 3 typedef long long LL; 4 using namespace std; 5 LL GCD(LL x, LL y) { 6 return y ? GCD(y, x % y) : x; 7 } 8 LL LCM(LL x, LL y) { 9 return x / GCD(x, y) * y; 10 } 11 LL cal(LL n, LL a, LL b) { 12 LL ans = 0; 13 LL x, y, tmp; 14 x = 0; 15 y = a; 16 for (LL i = a; i < n;) { 17 tmp = min(a - x, b - y); 18 if (i + tmp > n) { 19 tmp = n - i; 20 } 21 i += tmp; 22 ans += tmp * abs(x - y); 23 x = (x + tmp) % a; 24 y = (y + tmp) % b; 25 } 26 return ans; 27 } 28 int main() { 29 int T; 30 LL n, a, b; 31 LL lcm; 32 LL ans; 33 cin >> T; 34 while (T--) { 35 cin >> n >> a >> b; 36 if (a == b) { 37 ans = 0; 38 } else { 39 if (a > b) { 40 swap(a, b); 41 } 42 lcm = LCM(a, b); 43 ans = (n / lcm) * cal(lcm, a, b) + cal(n % lcm, a, b); 44 } 45 cout << ans << endl; 46 } 47 return 0; 48 }