P6685 可持久化动态仙人掌的直径问题 题解
话休絮烦,我们直接对本题的做法进行分析。
Solution 1 部分分做法
期望得分:
当
Solution 2A, 2B: 求幂
期望得分:
我们可以很容易地想到暴力枚举。为了加速,我们可以使用快速幂。
然而,运算的结果连 unsigned long long 和 __int128_t 都会爆掉,所以这种方法行不通。
既然整型存不下,我们不妨使用 pow 函数来求解。该函数返回的值是双精度浮点数,即 double。
| 数据类型 | 关键字 | 大小 | 范围 | 有效数字 |
|---|---|---|---|---|
| 单精度 | float | |||
| 双精度 | double |
此处,返回的类型可以达到
不过,pow 函数包括大部分浮点运算都存在严重的精度缺失问题,因此不能保证答案完全正确:
printf("%.0lf",pow(27,18));
//输出结果为58149737003040063952519168
print(999 ** 6) # Python中a**b表示a^b
print(pow(27, 18))
# 输出结果均为58149737003040059690390169
我们知道,Python 的 int 自带高精度,因此不存在精度问题。这就恰恰印证了 pow 函数确实有精度上的缺失。
然而,虽然 pow 函数精度不高,但由于
代码:
#include<bits/stdc++.h>
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;;i++)
{
if(pow(i,m)>n)
{
printf("%d",i-1);
return 0;
}
}
return 0;
}
Solution 3 求根
期望得分:
我们发现,当
由于
#include<bits/stdc++.h>
int n,m;
int main()
{
scanf("%d%d",&n,&m);
printf("%.0f",pow(n,1.0/m));
return 0;
}
Solution 4 对数
期望得分:
看到幂的运算,就能够想到对数。对数的定义:
如果
a^x=N (a \gt 0 且a \neq 1 ),则x=\log_a N 。
接下来就是对题目中不等号的处理。
不妨假设此时
然而,一般编程语言的数学库只包含以
因此需要用到换底公式:
把本题的数据代入得
由于
// 以 e 为底进行换底
#include<bits/stdc++.h>
int n,m;
int main()
{
scanf("%d%d",&n,&m);
printf("%.0f",floor(exp(log(n)/m))); // 必须加 floor 函数,因为 %.0f 默认四舍五入
return 0;
}
// 以 2 为底进行换底
#include<bits/stdc++.h>
int n,m;
int main()
{
scanf("%d%d",&n,&m);
printf("%.0f",floor(pow(2,log2(n)/m)));
return 0;
}
// 以 10 为底进行换底
#include<bits/stdc++.h>
int n,m;
int main()
{
scanf("%d%d",&n,&m);
printf("%.0f",floor(pow(10,log10(n)/m)));
return 0;
}
Solution 5 二分
期望得分:
由于当指数为正时乘方具有单调性,因此可以使用二分答案。
因为
题目中规定
二分每次需要判断
// 二分配合快速幂
#include<bits/stdc++.h>
int n,m,l=1,r,mid;
bool check(long long x,long long y) // 这里可以用 long long 存储的原因是 res 只要稍大于 n(n <= 10^9),该函数将直接返回 false
{
long long res=1;
while(y)
{
if(x>n)return false;
if(y&1)res*=x;
if(res>n)return false;
x*=x;
y>>=1;
}
return res<=n;
}
int main()
{
scanf("%d%d",&n,&m);
r=n;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid,m))l=mid+1;
else r=mid-1;
}
printf("%d",r);
return 0;
}
// 二分配合 pow 函数
#include<bits/stdc++.h>
int n,m,l=1,r,mid;
int main()
{
scanf("%d%d",&n,&m);
r=n;
while(l<=r)
{
mid=(l+r)>>1;
if(pow(mid,m)<=n)l=mid+1; // 与上述同理,pow 函数的精度在 10^9 范围内可以接受
else r=mid-1;
}
printf("%d",r);
return 0;
}