实用指南:洛谷P9560 [SDCPC 2023] Math Problem 题解

[SDCPC 2023] Math Problem

这题题解竟然没有满!

思路

有没有发现两个操作貌似相反?大家发现,假设先进行第一个操作再进行第二个管理,相当于没有进行管理。故最优的操作顺序一定是先进行若干次操作二,再进行若干次处理一。

那么我们可以枚举两次操作的次数。第二次操作最多进行log ⁡ k n \log_{k}{n}logkn次。如果初始为n nn,进行一次操作一,其可能的取值范围为[ n ⋅ k , n ⋅ k + k − 1 ] [n\cdot k,n\cdot k+k-1][nk,nk+k1],进行两次操作一,其可能的取值范围为[ n ⋅ k ⋅ k , ( n ⋅ k + k − 1 ) ⋅ k + k − 1 ] [n\cdot k\cdot k,(n\cdot k+k-1)\cdot k+k-1][nkk,(nk+k1)k+k1]。倘若当前取值范围为[ l , r ] [l,r][l,r],那么执行一次操作一后可能范围即为[ l ⋅ k , r ⋅ k + k − 1 ] [l\cdot k,r\cdot k+k-1][lk,rk+k1],该范围内的数都能取到。根据鸽巢原理,如果取值范围大于等于m mm,那么一定会有至少一个m mm的倍数,所以处理一最多执行log ⁡ k m \log_{k}{m}logkm次,总复杂度O ( T log ⁡ k n log ⁡ k m ) 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";
  else
  cout<<-1<<"\n";
  }
  return 0;
  }

posted on 2025-10-19 15:53  slgkaifa  阅读(6)  评论(0)    收藏  举报

导航