1 条题解

  • 0
    @ 2025-5-14 23:01:45

    题意分析

    有指数函数 kn=pk^n = p
    其中 kknnpp 均为整数且 1k1091 \leq k \leq 10^91n2001 \leq n \leq 2001p<101011 \leq p < 10^{101}
    给定 nnpp,求底数 kk

    解题思路

    考虑到数值存储问题和精度问题,这题最直观的思路应该是使用 高精度算法 求解。
    而事实上,这题也可用公式法求解,但需要一些技巧。

    开方公式:

    k=pnk = \sqrt[n]{p}

    但 C++ 的数学函数库并没有提供 kk 次方的开方函数,此时需要转换一下公式:

    k=p1/nk = p^{1/n}

    ppnn 次方等价于求 pp1/n1/n 次方,此时我们就可以用 pow 函数求解:

    k=pow(p,1.0/n)k = \text{pow}(p, 1.0/n)

    其实严格来说,如果这题没有限制 底数 kk 是整数,就不可能通过公式投机取巧。
    简单来说,如果要使用公式法,那么题目中所有运算都只能基于 double 类型进行(int 会溢出)。

    double 的取值范围为 103071030810^{-307} \sim 10^{308},但小数精度只有前 16 位(可自行搜索 double 的精度丢失问题)。
    也就是说,当我们用 double 存储 pp 的时候,它就已经开始出现误差,其误差范围在 101510^{-15} 的数量级左右。

    此时套用公式对 ppnn 次方根,须知开方运算是不会扩大误差范围的,
    所以 pn\sqrt[n]{p} 的小数位误差范围依旧在 101510^{-15} 的数量级以内。

    又因为 k=pnk = \sqrt[n]{p},亦即计算所得的 kk 的小数位误差范围也在 101510^{-15} 的数量级以内。
    显然这个误差级数仅会对 kk 的小数部分存在影响,四舍五入后对整数部分是无影响的。

    而题目已经限定了,nnkkpp 均是整数,因此使用公式法可以直接得到准确结果。

    标程

    #include <math.h>
    #include <iostream>
    using namespace std;
     
    int main(void) {
    	double n , p;
    	while(cin >> n >> p) {
    		double tmp = pow(p, 1 / n);	// p开n次方
    		int k = floor(tmp + 0.5);	// 四舍五入(+0.5后向下取整)
    		cout << k << endl;
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    1110
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    5
    已通过
    1
    上传者