Balls Rearrangement

Balls Rearrangement

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1128    Accepted Submission(s): 435


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.
 

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
网上关于这题的题解有很多。比我写的好的很多。我的目的是来记录一下自己的AC过程。以后注意自己的各种情况。 


这个题是周六那天做的 ,拿到这题我一看不是很难啊,于是就在纸上开始比划,比划一会我感觉有思路了,因为当时考虑到最小公倍数的情况了 所以对那些n,a,b的大小限制也就没太注意,于是就开始写了。 

#include<iostream>
#include<stdio.h>
using namespace std;
int arr1[100001];
int arr2[100001];
//求最小公倍数
int Minf(int a,int b)
{
    int x=a,y=b;
    int t;
    while(b!=0)
    {
        t=b; 
        b=a%b;
        a=t;
    }
    return x*y/a;
}
//求的是0到n的相差的数
int fun(int n)
{
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        if(arr1[i]>arr2[i])
        {
            sum+=arr1[i]-arr2[i];
        }
        else
        {
            sum+=arr2[i]-arr1[i];
        }
    }
    return sum;

}
int main()
{
    int cases;
    scanf("%d",&cases);
    while(cases--)
    {
        __int64 n,a,b;
        cin>>n>>a>>b;
        if(a==b)
        {
            printf("0\n");
            continue;
        }
        //我将每个球的盒子标号用数组表示了
        for(int i=1;i<=n;i++)
        {
            arr1[i]=(i-1)%a;
            arr2[i]=(i-1)%b;
        }
        int sum=0;
//因为没个最小公倍数都是一个循环嘛 也不多说
        int G = Minf(a,b);
        if(n>=G)
        {
            sum=fun(G)*(n/G);
            sum=sum+fun(n%G);
        }
        else
        {
            sum=fun(G);
        }
        printf("%d\n",sum);
    }
    return 0;
}

这是我第一次提交的代码。我自己感觉良好啊!但是提交结果 是错误答案。
我就开始找错误,因为自己写的嘛,固定思维,没找到。
我就放了放,等会再来找。后来我发现这个东西用数组存放根本不行 ,什么100000啊 比规定差得远了。
于是我就把数组去掉了。因为有无数组其实一个样。
于是修改了代码
#include<iostream>
#include<stdio.h>
using namespace std;
__int64 arr1;
__int64 arr2;
__int64 Minf(__int64 a,__int64 b)
{
    __int64 x=a,y=b;
    __int64 t;
    while(b!=0)
    {
        t=b; 
        b=a%b;
        a=t;
    }
    return x*y/a;
}
__int64 fun(__int64 n,__int64 a,__int64 b)
{
    __int64 sum=0;
	for(__int64 i=min(a,b);i<n;i++)
    {
		__int64 ans=(i)%a-(i)%b;
        if(ans>0)
        {
            sum+=ans;
        }
        else
        {
            sum+=(-ans);
        }
    }
    return sum;

}
int  main()
{
    __int64 cases;
    scanf("%d",&cases);
    while(cases--)
    {
        __int64 n,a,b;
        cin>>n>>a>>b;
        if(a==b)
        {
            printf("0\n");
            continue;
        }
        __int64 G = Minf(a,b);
		__int64 sum=0;
        if(n>=G)
        {
            sum=fun(G,a,b)*(n/G);
            sum=sum+fun(n%G,a,b);
        }
        else
        {
            sum=fun(n,a,b);
        }
        printf("%d\n",sum);
    }
    return 0;
}

进行了第二轮提交,结果超时了,唉!

苦思无果,上网搜了答案.
 找了好几个加上自己的比划好不容易看懂了。因为要不说的太繁琐,要不说的太少没看明白。
其实就是把球放到
a,b中第0个盒子之前的数都是一样的 
比如:
第三个例子:
    5  3
0  0   0   0
1  1   1   0
2  2   2   0
---------------
3  3  0    3
4  4   1   3
-----------------
5  0   2   2
----------------
6  1  0    1
7  2   1   1
8  3   2   1
---------------
9  4  0    4
10 5  1   4
比划一下是不是这些0之间的数都是相同的这一部分就不用多计算了。

于是就有了最后一个答案
#include<iostream>
#include<stdio.h>
using namespace std;
__int64 arr1;
__int64 arr2;
__int64 Minf(__int64 a,__int64 b)
{
    __int64 x=a,y=b;
    __int64 t;
    while(b!=0)
    {
        t=b; 
        b=a%b;
        a=t;
    }
    return x*y/a;
}
__int64 fun(__int64 n,__int64 a,__int64 b)
{
    __int64 sum=0;
	__int64 now=0;
	__int64 x=0,y=0;
	__int64 len=0;
	while(now<n)
	{
		len=min(a-x,b-y);
		if(n<now+len)
			len=n-now;
		sum+=len*(abs(x-y));
		now+=len;
		x=(x+len)%a;
		y=(y+len)%b;
	}
    return sum;

}
int  main()
{
    __int64 cases;
    scanf("%d",&cases);
    while(cases--)
    {
        __int64 n,a,b;
        cin>>n>>a>>b;
        if(a==b)
        {
            printf("0\n");
            continue;
        }
        __int64 G = Minf(a,b);
		__int64 sum=0;
        if(n>=G)
        {
            sum=fun(G,a,b)*(n/G);
            sum=sum+fun(n%G,a,b);
        }
        else
        {
            sum=fun(n,a,b);
        }
        cout<<sum<<endl;
    }
    return 0;
}

这次终于对了! 
要注意最后输出sum时我刚开始用的printf("%d",sum);错了
 好了。感谢自己,继续前行

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值