鱼香rose'Blog

2023山东ICPC省赛Problem E

\(\Huge{2023山东ICPC省赛Problem E. Math Problem}\)

比赛链接:Dashboard - The 13th Shandong ICPC Provincial Collegiate Programming Contest - Codeforces

官方题解:E - 数学问题 - SUA Wiki

题意

首先给出五个数字:\(n,k,m,a,b\);然后可以对n执行进行以下两种操作任意次:

  • 选择一个整数\(x(0 \le x \le k)\);令\(n=k\times n + x\),该操作每次花费\(a\)枚金币,每次选择的\(x\)可以不同。
  • 令$n=\left \lfloor \frac{n}{k} \right \rfloor \(,该操作每次花费\)b$枚金币。

求将\(n\)变为\(m\)的倍数最少需要花费几枚金币(\(0\)是任何正整数的倍数)。

数据范围:

  • (\(1\leq n\leq 10^{18}\), \(1\leq k, m, a, b\leq 10^9\))

思路

跟据两种操作,我们会发现,若执行一次操作①后,再执行一次操作②;那么这两次操作可以相互抵消,\(n\)的值不变。

因此我们会发现,执行完操作①之后将不再会执行操作②。

跟据题目数据范围可知,操作①和操作②之和不会超过\(200\)次,是比较小的。然后跟据上面的结论,我们可以暴力枚举先执行操作②的次数。

由于操作①有+x的情况,因此进行\(p\)次操作①后,\(n\)的范围为:\([k^p\times n_0,k^p\times (n_0+1)-1]\)(其中\(n_0\)\(n\)完成除法操作时的值),因此只要\(n\)在此区间即可停止乘法操作。

需要注意的是,在枚举的过程中,答案可能会超过long long范围,因此需要使用__int128__int128无法直接读入和输出,只能使用快读读入)。

其实我们在计算\(n\)的范围时,只需要将其对\(m\)取模即可,因为我们只需要判断当前\(n\)的值距离\(m\)的倍数的距离即可。

标程

#include<bits/stdc++.h>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
#define int long long 
#define ULL unsigned long long 
#define PII pair<int, int>
#define lowbit(x) (x & -x)
#define Mid ((l + r) >> 1)
#define ALL(x) x.begin(), x.end()
#define endl '\n'
#define fi first 
#define se second

const int INF = 0x7fffffff;
const int Mod = 1e9 + 7;
const int N = 2e5 + 10; 

void Solved() { 
    int n, k, m, a, b; cin >> n >> k >> m >> a >> b;
    if(n % m == 0) {cout << "0\n"; return;}
    if(k == 1) {cout << "-1\n"; return;}

    int res = 1e18, cost = 0;
    //双重循环,第一层枚举除的次数,第二层枚举乘的次数
    while(1) {
        int base = n % m, p = 1;
        for(int i = 0; ; i ++ ) {
            int d = (m - base) % m;//需要对m取模,表示距离每个m的倍数的位置
            // int d = m - base;
            // if(d == m) d = 0;
            if(d < p) {
                res = min(res, cost + i * a);
                break;
            }
            base = base * k % m;
            p = p * k;//对于x的累加不需取模
        }
        if(n == 0) break;
        n /= k;
        cost += b;
    }
    
    cout << res << endl;
}

signed main(void) {
    IOS

    int ALL = 1; 
    cin >> ALL;
    while(ALL -- ) Solved();
    // cout << fixed;//强制以小数形式显示
    // cout << setprecision(n); //保留n位小数

    return 0;
}
posted @ 2026-01-15 21:51  鱼香_rose  阅读(0)  评论(0)    收藏  举报