1 条题解

  • 0
    @ 2025-8-24 22:49:35

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar WhitD
    %$@oma

    搬运于2025-08-24 22:49:35,当前版本为作者最后更新于2023-09-14 20:26:25,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目大意

    给定两个正整数 nnkk,您可以进行以下两种操作任意次(包括零次):

    • 选择一个整数 xx 满足 0x<k0 \leq x < k,将 nn 变为 k×n+xk\times n+x。该操作每次花费 aa 枚金币,每次选择的整数 xx 可以不同。
    • nn 变为 nk\lfloor \frac{n}{k} \rfloor。该操作每次花费 bb 枚金币。其中 nk\lfloor \frac{n}{k} \rfloor 表示小于等于 nk\frac{n}{k} 的最大整数。

    给定正整数 mm,求将 nn 变为 mm 的倍数最少需要花费几枚金币。

    思路

    我们发现,先乘再除对结果是没有影响的(因为操作一加的值小于 kk,操作二的除法向下取整就把多加的数也除掉了),因此一定是先除再乘。

    我们假定当前的数为 nn,将它进行一次操作一:如果乘完了不加数,它会变成 n×kn\times k;如果乘完后加数,最多可以加 x(x<k)x(x<k),也就是 k1k-1,它会变成n×k+k1n\times k+k-1。这说明 nn 进行完操作一后可以变到的范围是 [n×k,n×k+k1][n\times k,n\times k+k-1]

    于是我们可以先枚举出进行操作二的次数(这个过程是 log\log 的),同时进行重复进行操作一直到 nn 成为 mm 的倍数(根据区间端点来判断是否在区间内),然后计算总代价,全局取 min\min 就可以了。

    注意特判 k=1k=1 是无解的。

    AC 代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int T;
    int main()
    {
    	cin>>T;
    	while(T--)
    	{
    		ll n,k,m,a,b,ans=114514191981011451;
    		cin>>n>>k>>m>>a>>b;
    		if(n%m==0)
    		{
    			cout<<0<<endl;
    			continue;
    		}
    		if(k==1)
    		{
    			cout<<-1<<endl;
    			continue;
    		}
    		for(ll i=0,d=0;;i++,n/=k,d=i*b)
    		{
    			if(!n)
    			{
    				ans=min(ans,b*i);
    				break;
    			}
    			__int128 l=n,r=n;
    			while(l%m&&(r/m==l/m))
    			{
    				r=r*k+k-1;
    				l*=k;
    				d+=a;
    			}
    			ans=min(ans,d);
    		}
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    9096
    时间
    4000ms
    内存
    1024MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者