hdu 4710

题目链接:https://vjudge.net/problem/HDU-4710
转自:https://blog.csdn.net/u011523796/article/details/11542497?utm_source=app
题意:有n个篮球,a个第一种篮子,b个第二种篮子。把篮球编号为0~n-1,把篮子分别编号为0 ~a-1,0 ~b-1。设篮球编号为x,把每个篮球放入编号为x%a的第一种篮子中,在把篮球放入编号为x%b的第二种篮子中,花费为原来所在篮子的编号-后来所在篮子的编号的绝对值,求总花费。
思路:1e9的数量级,直接遍历一遍都超时。有两个优化的地方:1.发现球的花费以a与b的最小公倍数为一个周期 2.若x是篮球编号,则从满足x%a=0||x%b=0的x开始到下一个x%a=0||x%b=0的前一位,它们的花费都是相同的。

#include <bits/stdc++.h>
using namespace std;
long long cal(long long n,long long a,long long b)
{
    long long now=0,temp=0,x=0,y=0,ans=0;
    while(now<n)
    {
        temp=min(a-x,b-y);//temp记录每次往后移动的位数 取最小值
        //也就是距离下一个x%a=0||x%b=0的距离
        if(now+temp>=n)//如果超出,就减去超出的部分
        {
            temp=n-now;
        }
        ans+=temp*abs(x-y);//统计答案
        x=(x+temp)%a;//x与y分别记录在0~a-1和0~b-1的位置
        y=(y+temp)%b;
        now+=temp;//now记录当前总位数
    }
    return ans;
}
int main()
{
    long long t,n,a,b;
    cin>>t;
    while(t--)
    {
        cin>>n>>a>>b;
        long long l=a*b/__gcd(a,b);//计算最小公倍数
        if(l>=n)//如果最小公倍数大于篮球数则不能按照公倍数拆分
        {
            cout<<cal(n,a,b)<<endl;
        }
        else//可以按照公倍数进行分块
        {//两部分分别为:一个周期内的花费*一共可以被分成几个周期+多余的
        //此处一定要注意n/l要加(),因为计算次序的问题所以一定要加
            cout<<cal(l,a,b)*(n/l)+cal(n%l,a,b)<<endl;
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值