题目大意:给出N, A 和B。N 代表有N个球, 原本N个球放在旧的A个箱子里面, 后来又买了B个新的箱子, 求要将N个球转移到新的箱子中需要多少移动距离。 放球的原则是 序号为 x 的球要放在 x mod A(或者B)序号的箱子里, 对于每个球的移动距离为| a - b |。
解题思路:因为N的上限是10^9, 所有不能对每个数进行 abs(x % a - x % b)后取和, 我的做法进行了两个优化。
1、首先,t = a * b, 0 ~ t - 1的移动距离是等于 t ~ 2 * t - 1的移动距离, (不一定是a * b, 具体来说是a 和b的最小公倍数。
2、其次,对于两条分界线中间的数来说, 移动距离也是相同的。
例如 : 11 5 3
0 1 2 / 3 4 | 5 / 6 7 8 / 9 |10 11 |
注意要用long long ,读入输出最好用cin , cout。
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
long long a, b;
long long solve(long long n) {
long long moveA = a, moveB = b, t = 0, cur, sum = 0;
while (1) {
if (moveA > moveB) {
cur = abs((moveB - 1) % a - (moveB - 1) % b);
sum += cur * (moveB - t);
t = moveB;
moveB += b;
}
else if (moveA < moveB) {
cur = abs((moveA - 1) % a - (moveA - 1) % b);
sum += cur * (moveA - t);
t = moveA;
moveA += a;
}
else {
cur = abs((moveA - 1) % a - (moveA - 1) % b);
sum += cur * (moveA - t);
t = moveA;
moveA += a;
moveB += b;
}
if (moveA > n && moveB > n) break;
}
sum += abs((n - 1) % a - (n - 1) % b) * (n - t);
return sum;
}
int main() {
int cas;
long long n, cur;
scanf("%d", &cas);
while (cas--) {
cin >> n >> a >> b;
if (a == b)
printf("0\n");
else {
cur = a * b;
long long sum = 0;
if (n / cur) sum += solve(cur) * (n / cur);
if (n % cur) sum += solve(n % cur);
cout << sum << endl;
}
}
return 0;
}