HDU 4611Balls Rearrangement(思维)

Balls Rearrangement

Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 1661    Accepted Submission(s): 627

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
 

 

Source
 

                题目大意:刚开始比赛的时候,一看见这题,以为是水题。是自己想简单了。题目是这样:给你n个球编号0~n-1,先放进a个箱子里,i mod a =p,第i个球放在箱子p里面,就是同模的放在一起。然后再把这些球移到b个箱子里面,同样的法则。sum值等于每个球从i号箱子移到j号箱子的数目总和。一个球的sum=abs(i-j).

          解题思路:开始把他想简单了,这些球都是有唯一的标识的。后来想清楚了之后,发现循环节是mi(n,lcm(a,b))但是直接用循环节统计会TLE。如果a取9999,b取9997,n=10^9那么循环节直接是10^9。肯定会TLE。然后又开始找规律,突然发现可以用两个指针不断地移动。不用每次都是++,自己可以在纸上画一下。
0 1 2 3 4     0 1 2
5 6 7 8 9     3 4 5
10            6 7 8
              9 10
如果到6的时候,左边一行可以到9,右边一行可以到8.我们选取小的。会发现6~8之间abs(i-j)是一样的。同理0可以直接跳到3那里。主要就是用到这个思想。详见代码。当时因为没有用__int64Wa了好半天!!!

          题目地址:Balls Rearrangement

AC代码:
0 1 2 3 4     0 1 2
5 6 7 8 9     3 4 5
10            6 7 8
              9 10

#include<iostream>
#include<cstdio>
using namespace std;

__int64 f(__int64 x)
{
    if(x<0)
        x=-x;
    return x;
}
__int64 gcd(__int64 m,__int64 n)
{
    __int64 t;
    while(n)
    {
        t=m%n; m=n; n=t;
    }
    return m;
}

__int64 min1(__int64 x1,__int64 x2)
{
    if(x1<x2) return x1;
    else return x2;
}

int main()
{
    __int64 mi,p,a,b,i,j,t1,t2,cnt,sum,tes;
    __int64 lcm;
    scanf("%I64d",&tes);
    while(tes--)
    {
        scanf("%I64d%I64d%I64d",&p,&a,&b);
        if(a==b)
        {
           puts("0");
           continue;
        }
        lcm=a/gcd(a,b)*b;   //a,b的最小公倍数
        mi=p;
        if(mi>lcm)
            mi=lcm;   //mi是循环节
        t1=p/mi,t2=p%mi;
        cnt=0,i=0,j=0;
        sum=0;

        __int64 mi2;
        while(cnt<mi)  //一个循环内的
        {
            if(i>=a) i-=a;
            if(j>=b) j-=b;
            mi2=min1(a-i,b-j);
            if(mi2>mi-cnt)  //这点需要注意,不能超过步数
                mi2=mi-cnt;
            sum+=f(i-j)*mi2;
            i+=mi2; j+=mi2; cnt+=mi2;
        }
        sum=sum*t1;
        cnt=0,i=0,j=0;
        while(cnt<t2)  //循环节以外的
        {
            if(i>=a) i-=a;
            if(j>=b) j-=b;
            mi2=min1(a-i,b-j);
            if(mi2>t2-cnt)
                mi2=t2-cnt;
            sum+=f(i-j)*mi2;
            i+=mi2; j+=mi2; cnt+=mi2;
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

/*
23
1000000000 1 1
8 2 4
11 5 3
1000000000 9999 9997
*/


 

转载于:https://www.cnblogs.com/james1207/p/3281349.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值