洛谷P9560 [SDCPC 2023] Math Problem 题解
[SDCPC 2023] Math Problem
这题题解竟然没有满!
思路
有没有发现两个操作貌似相反?我们发现,如果先进行第一个操作再进行第二个操作,相当于没有进行操作。故最优的操作顺序一定是先进行若干次操作二,再进行若干次操作一。
那么我们可以枚举两次操作的次数。第二次操作最多进行 logkn\log_{k}{n}logkn 次。如果初始为 nnn,进行一次操作一,其可能的取值范围为 [n⋅k,n⋅k+k−1][n\cdot k,n\cdot k+k-1][n⋅k,n⋅k+k−1],进行两次操作一,其可能的取值范围为 [n⋅k⋅k,(n⋅k+k−1)⋅k+k−1][n\cdot k\cdot k,(n\cdot k+k-1)\cdot k+k-1][n⋅k⋅k,(n⋅k+k−1)⋅k+k−1]。如果当前取值范围为 [l,r][l,r][l,r],那么执行一次操作一后可能范围即为 [l⋅k,r⋅k+k−1][l\cdot k,r\cdot k+k-1][l⋅k,r⋅k+k−1],这个范围内的数都能取到。根据鸽巢原理,如果取值范围大于等于 mmm,那么一定会有至少一个 mmm 的倍数,所以操作一最多执行 logkm\log_{k}{m}logkm 次,总复杂度 O(Tlogknlogkm)O(T\log_{k}{n}\log_{k}{m})O(Tlogknlogkm)。
代码
有可能爆 long long,要开 __int128!
#include<bits/stdc++.h>
using namespace std;
int t,k,m,a,b;
long long p[70],cnt,n;
int main()
{ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>t;while(t--){cin>>n>>k>>m>>a>>b;cnt=1,p[1]=n;while(k!=1&&n!=0)//p中记录所有操作二的可能结果{n/=k;p[++cnt]=n;}long long ans=1e18;for(int i=1;i<=cnt;i++){if(k==1)//k=1要特判{if(p[i]%m==0)ans=min(ans,1ll*(i-1)*b);continue ;}__int128 l=p[i],r=p[i];long long sum=1ll*(i-1)*b;while(l/m==r/m&&l%m!=0&&r%m!=0){l*=k,r*=k;r+=k-1;sum+=a;}ans=min(ans,sum);}if(ans!=1e18)cout<<ans<<"\n";elsecout<<-1<<"\n";}return 0;
}