#P2792. 第1题-整数的最小花费
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 112
            Accepted: 39
            Difficulty: 4
            
          
          
          
                       所属公司 : 
                              美团
                                
            
                        
              时间 :2025年4月5日-开发岗
                              
                      
          
 
- 
                        算法标签>暴力枚举          
 
第1题-整数的最小花费
题解
题面描述
给定一个初始整数n和目标数m,要求通过若干次操作使得n的值不小于m。有两种操作:
- 操作一:将n更新为2×n,花费为w2。
 - 操作二:将n更新为3×n,花费为w3。
 
问题要求在若干次操作后使得n≥m,求最小花费。
思路
由于每次操作都是将n乘以固定的数(2或3),那么无论操作的顺序如何,最终结果都是n×2a×3b,其中a和b分别是两种操作的次数。目标是找到非负整数a和b,使得
n×2a×3b≥m且花费最小,花费计算为
cost=a×w2+b×w3考虑到n和m的范围很大,但由于操作每次都会快速增大n,所需要的a和b不会太大(例如,若只用倍增操作,a≤31即可;若只用乘3操作,b也在几十以内),因此可以枚举a和b的所有可能组合,然后取满足条件的最小花费。
代码分析
- 
判断边界情况:若初始n≥m则不需要任何操作,花费为0。
 - 
枚举操作次数:设a和b的上限为一个足够大的数(如32),遍历所有可能的组合。
 - 
计算结果并更新最小花费:对于每一组(a,b),计算n×2a×3b,若大于等于m,则计算花费cost=a×w2+b×w3,取所有满足条件的最小值。
 - 
输出答案:枚举完成后输出最小花费。
 
C++
#include <iostream>
#include <cstdint>
#include <algorithm>
using namespace std;
int main(){
    int T;
    cin >> T;
    while(T--){
        // 输入 n, m, w2,w3
        uint64_t n, m;
        int w2, w3;
        cin >> n >> m >> w2 >> w3;
        
        if(n >= m){
            cout << 0 << endl;
            continue;
        }
        
        // 初始化最小花费为一个较大值
        uint64_t ans = (uint64_t)1e18;
        
        // 枚举a和b的取值范围。由于数据范围,枚举上限取32足够
        for(int a = 0; a < 32; a++){
            // 预先计算2^a
            uint64_t pow2 = 1ULL << a; // 等同于2^a
            if(n * pow2 >= m){
                ans = min(ans, (uint64_t)a * w2);
                break;
            }
            // 枚举b
            uint64_t cur2 = n * pow2;
            uint64_t pow3 = 1;
            for(int b = 0; b < 32; b++){
                // 更新乘以3^b
                if(b > 0) pow3 *= 3;
                if(cur2 * pow3 >= m){
                    uint64_t cost = (uint64_t)a * w2 + (uint64_t)b * w3;
                    ans = min(ans, cost);
                    break; // 增加更多b只会使花费更高
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}
Python
# 读取测试数据组数
T = int(input())
for _ in range(T):
    # 输入 n, m, w_2, w_3
    n, m, w2, w3 = map(int, input().split())
    
    if n >= m:
        print(0)
        continue
    
    ans = float('inf')
    
    # 枚举a的取值,使用32作为上限
    for a in range(32):
        pow2 = 1 << a  # 计算2^a
        if n * pow2 >= m:
            ans = min(ans, a * w2)
            break
        cur2 = n * pow2
        pow3 = 1
        # 枚举b的取值
        for b in range(32):
            if b > 0:
                pow3 *= 3  # 计算3^b
            if cur2 * pow3 >= m:
                cost = a * w2 + b * w3
                ans = min(ans, cost)
                break  # 增加b只会增加花费
    print(ans)
Java
import java.util.Scanner;
public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        // 读取测试数据组数
        int T = sc.nextInt();
        for(int t = 0; t < T; t++){
            // 输入 n, m, w_2, w_3
            long n = sc.nextLong();
            long m = sc.nextLong();
            int w2 = sc.nextInt();
            int w3 = sc.nextInt();
            
      
            if(n >= m){
                System.out.println(0);
                continue;
            }
            
            long ans = Long.MAX_VALUE;
            
            // 枚举a的取值,取值上限为32
            for(int a = 0; a < 32; a++){
                long pow2 = 1L << a;  // 计算2^a
                if(n * pow2 >= m){
                    ans = Math.min(ans, (long)a * w2);
                    break;
                }
                long cur2 = n * pow2;
                long pow3 = 1;
                // 枚举b的取值,取值上限为32
                for(int b = 0; b < 32; b++){
                    if(b > 0) {
                        pow3 *= 3;  // 计算3^b
                    }
                    if(cur2 * pow3 >= m){
                        long cost = (long)a * w2 + (long)b * w3;
                        ans = Math.min(ans, cost);
                        break;  // 增加b会增加花费,故直接跳出
                    }
                }
            }
            System.out.println(ans);
        }
        sc.close();
    }
}
        题目内容
开始有一个整数 n ,你需要经过若干次操作,使 n 的值不小于 m 。
操作一:将 n 更改为 2∗n ,花费为 w2 ;
操作二:将 n 更改为 3∗n ,花费为 w3 。
请输出需要的最小花费。
输入描述
输入第一行一个整数 T ,代表接下来有 T 组测试数据。
接下来 T 行,每行有 4 个整数 n,m,w2,w3
1≤T≤10000
1≤n,m≤231−1
1≤w2,w3≤1000
输出描述
对于每组测试数据,输出一行,一个整数代表最小花费
样例1
输入
4
1 6 2 3
4 32 3 4
2 1 1 2
1 2147483647 1 4
输出
5
8
0
31