HDU 4611
对于任意a,b,只要最多计算一遍循环节就行了。
对于这样的题目,明了的程序结构比解法更重要。
#include <cstdio> #include <cstring> using std::memset; long long t, n, a, b; long long max(long long a, long long b) { return a < b? b : a; } long long min(long long a, long long b) { return a < b? a : b; } long long abs(long long a) { return a > 0? a : -a; } long long gcd(long long a, long long b) { return b?gcd(b, a%b): a; } long long count(long long l,long long a, long long b) { long long ans = 0; long long sa = 0, sb = 0; while(sa < l && sb < l) { long long from = max(sa, sb); long long to = min(sa+a, sb+b); if(to >= l) { break; } ans += (to - from) * abs( from % a - from % b); if(sa + a < sb + b) { sa = to; } else { sb = to; } } long long from = max(sa, sb); ans += (l - from) * abs(from%a - from%b); return ans; } int main() { scanf("%I64d", &t); while(t--) { scanf("%I64d%I64d%I64d", &n, &a, &b); long long ans = 0; long long lcm = a*b/gcd(a, b); if( n > lcm) { ans += count(lcm, a, b) * (n/lcm) + count(n%lcm, a, b); } else { ans = count(n, a, b); } printf("%I64d\n", ans); } }