HDU 4710 Balls Rearrangement

 

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.
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).
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


题目大意:刚开始的时候bob有n个球和A个箱子,bob把球标号为0~n-1,标号为t的球放进第t%A个箱子里。现在bob又买了B个新箱子又用同样的方法吧标号为t的球放进第t%B个箱子里,每次把球从A箱子拿出来放进B箱子会有花费,为 |n%A-n%B| 求出移动所有的球的总的花费。

这个题明显能看得出来每隔LCM(A,B)为一个循环,所以刚开始想的是只需要求一个循环的花费乘循环次数最后再加上不足一个循环的花费就是结果,但是看了一下A和B的数据量,当A和B很大的时候可能n还没有LCM(A,B)大,所以如果只有这一个规律肯定是超时的。我们可以把一个循环的所有数写出来(就用实例的3和5就可以)。

               0  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18.....

A(3):0  1  2  0  1  2  0  1  2  0   1     2    0    1     2    0     1    2     0

B(5):0  1  2  3  4  0  1  2  3  4   0     1    2    3     4    0     1    2     3

差            0  0  0  3  3  2  1  1  1  4   1     1    2    2     2    0     0    0     3


我们可以看出当A,B都为0时就是一个循环,而且每两个零之间的差值都是相等的所以我们不必一个个数的加。只需算出每一段的第一个差值,然后乘上长度就可以。

代码还可以改进,但我懒得改了就先这样吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
ll GCD(ll a,ll b){
	return b?GCD(b,a%b):a;
}
ll LCM(ll a,ll b){
	return a*b/GCD(a,b);
}

int main()
{
	ll n,A,B;
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%lld",&n);
		scanf("%lld%lld",&A,&B);
		ll aa=A,bb=B;
		ll lcm=LCM(A,B);
		ll t=0,ans=0;
		if(n>=lcm){//求每一个LCM的差值的和
			while(1){
				if(aa+A<bb){
					ans+=A*(ll)abs(aa%A-aa%B);
					aa+=A;
				}
				else if(bb+B<aa){
					ans+=B*(ll)abs(bb%A-bb%B);
					bb+=B;
				}
				else if(aa>bb){
					ans+=(aa-bb)*(ll)abs(bb%A-bb%B);
					bb+=B;
				}
				else if(aa<bb){
					ans+=(bb-aa)*(ll)abs(aa%A-aa%B);
					aa+=A;
				}
				else
					break;
			}
			t=n%lcm;
		}
		else{
			t=n;
		}
		ans=ans*(n/lcm);
		aa=A;bb=B;
		while(t>min(aa,bb)){//求多余的部分差值的和
			if(aa+A<bb){
				if(aa+A>t){
					ans+=(t-aa)*(ll)abs(aa%A-aa%B);
					break;
				}
				ans+=A*(ll)abs(aa%A-aa%B);
				aa+=A;
			}
			else if(bb+B<aa){
				if(bb+B>t){
					ans+=(t-bb)*(ll)abs(bb%A-bb%B);
					break;
				}
				ans+=B*(ll)abs(bb%A-bb%B);
				bb+=B;
			}
			else if(aa>bb){
				if(aa>t){
					ans+=(t-bb)*(ll)abs(bb%A-bb%B);
					break;
				}
				ans+=(aa-bb)*(ll)abs(bb%A-bb%B);
				bb+=B;
			}
			else if(aa<bb){
				if(bb>t){
					ans+=(t-aa)*(ll)abs(aa%A-aa%B);
					break;
				}
				ans+=(bb-aa)*(ll)abs(aa%A-aa%B);
				aa+=A;
			}
			else
				break;
		}
		printf("%lld\n",ans);
	}
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值