HDU 4611 数学+YY

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.
 

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
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整除的,一部分是剩下的,累加即可。
#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;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值