Balls Rearrangement
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 2447 Accepted Submission(s): 886
Problem Description
Bob has N balls and A boxes. He numbers the balls from 0 to N-1, and numbers the boxes from 0 to A-1. To find the balls easily, he puts the ball numbered x into the box numbered a if x = a mod A. Some day Bob buys B new boxes, and he wants to rearrange the balls from the old boxes to the new boxes. The new boxes are numbered from 0 to B-1. After the rearrangement, the ball numbered x should be in the box number b if x = b mod B.
This work may be very boring, so he wants to know the cost before the rearrangement. If he moves a ball from the old box numbered a to the new box numbered b, the cost he considered would be |a-b|. The total cost is the sum of the cost to move every ball, and it is what Bob is interested in now.
This work may be very boring, so he wants to know the cost before the rearrangement. If he moves a ball from the old box numbered a to the new box numbered b, the cost he considered would be |a-b|. The total cost is the sum of the cost to move every ball, and it is what Bob is interested in now.
Input
The first line of the input is an integer T, the number of test cases.(0<T<=50)
Then T test case followed. The only line of each test case are three integers N, A and B.(1<=N<=1000000000, 1<=A,B<=100000).
Then T test case followed. The only line of each test case are three integers N, A and B.(1<=N<=1000000000, 1<=A,B<=100000).
Output
For each test case, output the total cost.
Sample Input
3 1000000000 1 1 8 2 4 11 5 3
Sample Output
0 8 16
Source
2013 Multi-University Training Contest 2
题意求
n-1
∑ abs(i%a-i%b)的值
i=0
n=10^9 1S暴力肯定跪,列表发现,lcm(a,b)为其中一个循环节,因此只要处理一个循环节里的数就好,但是若a,b足够大gcd(a,b)互素,则值仍然很大,还是会跪(我卖了个萌写了直接T了),后来大湿说要对循环节内部分块处理,后来发现一开始有几个0,可以省略,但是根本没用,后来发现表中总有一段的值是相同的即取模差值的绝对值相同记为abs(x-y),所以没必要依次循环下去,可以每次找出连续相等的值的个数,分段处理,至于如何找到的,这是我YY出来的,发现每次都是加一个tmp而且首先这个tmp=min(a,b),然后跳几步跟当前步数(tmp+x)%a 和(tmp+y)%b二者的较小者有关(初始xy都为0,yy起来真心不容易,画了三个表在找规律...),最后还要考虑如果加上了这个跳跃的步数比n大的情况的处理(这个没考虑到WA了一次)剩下的过程就很简单了,如果lcm>=n直接处理n,否则分两部分处理,一部分是可以被lcm整除的,一部分是剩下的,累加即可。
题意求
n-1
∑ abs(i%a-i%b)的值
i=0
n=10^9 1S暴力肯定跪,列表发现,lcm(a,b)为其中一个循环节,因此只要处理一个循环节里的数就好,但是若a,b足够大gcd(a,b)互素,则值仍然很大,还是会跪(我卖了个萌写了直接T了),后来大湿说要对循环节内部分块处理,后来发现一开始有几个0,可以省略,但是根本没用,后来发现表中总有一段的值是相同的即取模差值的绝对值相同记为abs(x-y),所以没必要依次循环下去,可以每次找出连续相等的值的个数,分段处理,至于如何找到的,这是我YY出来的,发现每次都是加一个tmp而且首先这个tmp=min(a,b),然后跳几步跟当前步数(tmp+x)%a 和(tmp+y)%b二者的较小者有关(初始xy都为0,yy起来真心不容易,画了三个表在找规律...),最后还要考虑如果加上了这个跳跃的步数比n大的情况的处理(这个没考虑到WA了一次)剩下的过程就很简单了,如果lcm>=n直接处理n,否则分两部分处理,一部分是可以被lcm整除的,一部分是剩下的,累加即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int t;
long long n,a,b;
long long gcd(long long a,long long b)
{
if(b==0)
return a;
else
return gcd(b,a%b);
}
long long lcm(long long a,long long b)
{
return a/gcd(a,b)*b;
}
long long slove(long long a,long long b,long long n)
{
long long now=0;
long long ans=0;
long long tmp;
long long x=0,y=0;
while(now<n)
{
tmp=min(a-x,b-y);
if (now+tmp>n) tmp=n-now;
ans+=tmp*abs(x-y);
x=(x+tmp)%a;
y=(y+tmp)%b;
now+=tmp;
//cout<<tmp<<"~~"<<x<<"~"<<y<<"~"<<ans<<endl;
}
return ans;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n>>a>>b;
long long ans;
long long l=lcm(a,b);
if(l>=n)
ans=slove(a,b,n);
else
ans=slove(a,b,l)*(n/l)+slove(a,b,n%l);
cout<<ans<<endl;
}
return 0;
}