首页 > 试题广场 >

幂次进近

[编程题]幂次进近
  • 热度指数:2586 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定 t 次询问,每次询问给出两个正整数 nk
请你找到最小的正整数 m ,使得 n-m^k绝对值最小。

输入描述:
第一行有一个整数 t\ (\ 1 \leq t \leq 10^5\ )
随后 t 行,每行两个整数 n,k\ (\ 1 \leq n,k \leq 10^{18}\ )


输出描述:
输出 t 行,每行一个正整数 m
示例1

输入

3
6 2
1 1
78 3

输出

2
1
4
示例2

输入

3
114 514
1000000000 2
1000000000000000000 3

输出

1
31623
1000000

备注:
如果你使用 python 编写代码,请提交到 pypy3
我讨厌这道题
发表于 2026-02-04 11:22:29 回复(5)

本题数比较大,所以可以用py解决,但是py也需要特判三个点,不然会超时

k=1时直接输出n

k>60直接输出1,因为(2**61 > 1e18),大于 60 的 k,整数根可能只有 1

n=1直接输出1

代码如下:

作者:pandaC222
链接:https://www.nowcoder.com/discuss/848563961992581120
来源:牛客网
def fastpow(a,b):
    ans=1
    while b!=0:
        if b&1:
            ans*=a
        b>>=1
        a*=a
    return ans
t=int(input())
for _ in range(t):
    n,k=map(int,input().split())
    if k==1:
        print(n)
        continue
    if n==1&nbs***bsp;k>60:
        print(1)
        continue
    l=0
    r=10**18
    while l+1<r:
        mid=(l+r)//2
        if fastpow(mid,k)<=n:
            l=mid
        else:
            r=mid
    res1=abs(n-fastpow(l,k))
    res2=abs(n-fastpow(l+1,k))
    if res1>res2:
        print(l+1)
    else:
        print(l)
发表于 2026-02-04 14:10:49 回复(2)
我们将使用拉马努金瞪眼法解决这一题
注意到,本题考察启发式算法/int128/python语法基础
如果 k==1,那么显然 m==n
如果 k 很小,那么你可以使用三分进行查找
如果 k 较大,反正 n 不会超过 1e18 ,直接枚举
如果 k 很大,那么即便是 m==2,也会使得答案极大m==1 最好
铃仙并不想写 py,因为太熟练,也没学过 int128 使用,直接 ai 了一份
所以正解到底是什么?
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>

using namespace std;

// 将 ll 定义为 __int128
typedef __int128 ll;

// 手写适配 __int128 的快读
ll qd() {
    ll x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + (ch - '0');
        ch = getchar();
    }
    return x * f;
}

// 手写适配 __int128 的快写
void write(ll x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9) write(x / 10);
    putchar((long long)(x % 10) + '0');
}

// 手写绝对值和最大值函数,避免标准库类型匹配冲突
ll my_abs(ll a) { return a < 0 ? -a : a; }
ll my_max(ll a, ll b) { return a > b ? a : b; }

void solve() {
    ll n = qd();
    ll k = qd();

    // 特判 k=1
    if (k == 1) {
        write(n);
        putchar('\n');
        return;
    }

    // 特判 k 很大,m 只能是 1 或 2 的情况
    if (k >= 62) {
      
        write(1);
        putchar('\n');
        return;
    }

    // 获取近似根 x
    // 注意:pow 必须传 double,所以这里强制转一下
    ll x = (ll)pow((double)n, 1.0 / (double)k);

    ll best_m = 1;
    ll min_diff = -1;

    // 检查 x 附近的整数,解决 pow 精度带来的 +-1 误差
    // 范围取 [max(1, x-2), x+2]
    ll start_m = my_max(1, x - 2);
    for (ll m = start_m; m <= x + 2; m++) {
        // 计算 m^k
        ll val = 1;
        bool overflow_risk = false;
        for (int i = 0; i < (long long)k; i++) {
            // 简单的溢出保护:如果当前值已经远超 n,再乘下去差值只会更大
            if (i > 0 && val > (n + 2e18)) {
                overflow_risk = true;
                break;
            }
            val *= m;
        }

        ll diff = my_abs(n - val);

        if (min_diff == -1 || diff < min_diff) {
            min_diff = diff;
            best_m = m;
        }
        else if (diff == min_diff) {
            // 如果差值一样,取更小的 m
            if (m < best_m) best_m = m;
        }
    }

    write(best_m);
    putchar('\n');
}

int main() {
    // 读取测试用例数量 t
    long long t_long;
    if (scanf("%lld", &t_long) != EOF) {
        while (t_long--) {
            solve();
        }
    }
    return 0;
}
/*
⡀⠎⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣄⠃⠈⣶⡛⠿⠭⣉⠛⠿⡿⠛⠉⣀⣠⣤⣭⡏⠴⢀⣴⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣷⣱⣬⠛⠉⠀⠀⢠⠀⠀⠀⢀⣀⠀⠉⠿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠈⡿
⠀⠀⠀⠀⠀⠀⠀⢀⢿⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⡏⠀⠀⠀⠀⠈⠳⠀⠀⠀⠻⣿⣿⣿⣿⣿⣿⠋⠀⣇⠀⠀⠀⠀⠀⠀⠀⠀⠈
⠀⠀⠀⠀⠀⠀⠀⣸⠀⣿⣿⣿⣿⠟⠀⠀⠀⠂⠀⠀⢠⠀⠀⠀⠀⠀⠀⠀⠈⡀⠀⠀⠀⠻⣿⣿⣿⣿⣷⡀⠘
⠀⠀⠀⠀⠀⠀⠀⣧⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣄⣧
⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⣾⠀⠀⠀⠀⠀⠀⠀⠀⠀⢧⠀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣿⣆
⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⢂⠻⣿⣿⣿⣿⣿⣄
⠀⠀⠀⠀⠀⣿⣿⣿⣿⣹⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⠀⠀⠀⠀⠀⡄⠈⢿⣿⣿⣿⣿⣆
⠀⠀⠀⠀⣿⣿⣿⣿⠁⡇⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠐⠸⠀⠀⠻⣿⣿⣿⣆⢦
⠀⠀⢠⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⣼⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡏⣧⠀⠀⠀⠀⠐⣇⠀⠀⠙⣿⣿⣿⡄⠙⣄
⠀⣴⣿⣿⣿⣿⠏⠀⢸⠀⠀⠀⠀⠀⠀⡿⢿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣃⣈⣦⠀⠀⠀⠀⢹⠀⠀⠀⠸⣿⣿⣿⠀⠀⠳⣀
⠋⣸⣿⣿⣿⡟⠀⠀⠀⡆⠀⠀⠀⠀⠀⡏⠙⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⢠⠀⠀⠀⢧⠀⠀⠀⠀⡇⠀⠀⠀⠘⣿⣿⣷⠀⠀⠘
⠀⣿⣿⣿⢩⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⣀⠀⢱⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠂⢀⣴⣶⣿⣿⡀⠀⠀⢻⠀⠀⠀⠀⠹⣿⣿⡄
⢸⣿⣿⠃⠈⠀⠀⢸⠀⣿⣆⠀⠀⠀⠀⣿⣿⣿⠷⠘⡀⠀⠀⠀⠀⠀⠀⢠⢹⡀⠈⡿⠻⣿⣛⢿⣿⣷⡀⠈⠀⠀⠀⠀⠀⢻⣿⣿
⣿⣿⣿⠀⠀⠀⠀⢸⠀⡇⣼⣄⠀⠀⠀⢻⣿⡄⠑⠑⣿⡀⠀⠀⠀⢀⠀⠂⠇⠀⠀⠖⠛⢿⣿⣿⣌⢿⣿⣿⡆⠀⠀⠀⠀⠀⣿⣿⡀
⣿⣿⡇⠀⠀⠀⠀⢸⠀⣾⣿⣿⡷⠿⣷⣤⣿⣿⡄⠀⠀⠀⠑⠤⡀⠀⠃⠀⠀⠀⠀⣿⣶⣿⣿⣿⣿⣆⠙⣿⣧⠀⠀⠀⠀⠀⣿⣿⡇
⣿⣿⠁⠀⠀⠀⠀⠘⣾⣿⣿⠁⣴⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠸⡏⠙⣿⠉⠻⣿⠀⠀⣿⠀⠀⠀⣄⠀⣿⢸⣷
⣿⣿⡇⠀⠀⠀⠀⠀⣿⣿⠁⠀⣿⣿⠋⣿⠏⠙⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠀⢀⢻⠀⠀⢀⡟⢀⣿⣸⢃⠟
⣿⣿⣿⠀⡄⠀⠀⠀⠘⠻⡄⠀⢹⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⠀⢀⣿⠃⣿⣿⡗⠁
⣧⣿⣿⣧⢹⡀⠀⠀⠀⠱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⣴⣿⣿⣾⣿⣿⣿
⢿⠘⣿⣿⣿⣿⣤⠀⠢⡀⠱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣵⣿⣿⣿⣿⣿⣿⣿⣿⣷
⠀⠉⣿⣿⣿⡿⣿⠻⣷⣬⣓⣬⣄⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠉⠈⠈⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⠃⠼⢉⣿⣿⣿⣿⣿⣿⣿
⠀⠀⣿⣿⣿⣷⠀⠀⠀⠘⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⡏⠀⠀⢸⠀⢻⢿⣿⣿⡏⣿
⠀⢸⣿⣿⣿⣿⠀⠀⠀⠀⢻⣿⣿⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⠀⠀⠀⢸⠀⠀⢸⣿⣿⠘⡀
⢦⡿⣿⣿⣿⢿⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣶⣶⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠘⡄⠀⠈⣿⣿⡄⠱
⣴⠛⣾⣿⣿⢸⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⡄⠀⠀⠀⠀⠀⠀⠀⣯⠛⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⣇⠀⠀⣿⣿⣿
⠿⠀⣿⣿⣿⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠟⠰⡾⠃⠀⠀⠀⠀⠀⠀⠀⠙⡟⠀⢻⣿⣿⣿⣿⣿⡆⠀⠀⠀⠸⠀⠀⠸⣿⣿⣷
⠆⢳⣿⣿⡇⠀⠀⠀⠀⠀⠀⣿⣿⣿⠛⠿⠿⢿⡟⠀⠀⠉⠦⣀⡤⢶⠀⠖⠲⠶⠊⠀⠀⠀⢻⡛⠛⠛⣿⣿⠀⠀⠀⠀⠃⠀⠀⢿⣿⣿
*/


发表于 2026-02-04 21:24:37 回复(0)
//算法练习No.9
//数学构造+边界处理
#include <iostream>
#include <cmath>
using namespace std;

typedef __int128_t int128;

void solve()
{
    long long n,k;
    cin >> n >> k;

    if(k == 1)
    {
        cout << n << endl;//m=n,结果为0
        return;
    }

    if(k >= 62)
    {
        cout << 1 << endl;//
        return;
    }

    //不大不小的情况
    long long m = pow(n,1.0/k);//m == n^1/k
    if(m == 0) m = 1;
    //比较m^k 与 m+1^k
    int128 a {1};
    int128 b {1};
    for(int i = 0;i<k;i++) a *= m;
    for(int i = 0;i<k;i++) b *= (m+1);
    //int128 不能直接用 abs
    int128 c = (a>(int128)n)?(a-n):(n-a);
    int128 d = (b>(int128)n)?(b-n):(n-b);

    if(c > d)
    {
        cout << m+1 << endl;
    }
    else
    {
        cout << m << endl;
    }

}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int t;
    cin >> t;
    while(t--)
    {
        solve();
    }
   
    return 0;
}
// 64 位输出请用 printf("%lld")
发表于 2026-02-04 17:14:32 回复(0)