P10320 勇气(Courage) 题解
题目大意
给定两个整数 x , n x,n x,n 和一种变换方式,要求求出最少经过多少次变换之后 x x x 的值不小于 2 n 2^n 2n。
上面所提到的“变换方式”如果使用函数来进行刻画的话,其表达式为:
f ( x i ) = { x 2 , i = 1 ( f ( x i − 1 ) 2 ) 2 , i > 1 f(x_i)=\left\{ \begin{array}{rcl} x^2, & & & i=1\\ (\frac{f(x_{i-1})}{2})^2, & &&i > 1 \end{array} \right. f(xi)={x2,(2f(xi−1))2,i=1i>1
其中, f ( x i ) f(x_i) f(xi) 代表的是经过第 i i i 次变换后得到的数值。
变换分析
首先,我们先在小范围内进行模拟计算,其初始值为 x x x。为了更加直观的展示每组数据的由来,特地列出了原始的表达式和最后化简的表达式,如下表所示:
变换次数 | 原始表达式 | 化简表达式 |
---|---|---|
0 0 0 | x x x | x x x |
1 1 1 | ( x 2 0 ) 2 \left(\frac{x}{2^0}\right)^2 (20x)2 | x 2 2 0 \frac{x^2}{2^0} 20x2 |
2 2 2 | ( x 2 2 ) 2 \left(\frac{x^2}{2}\right)^2 (2x2)2 | x 4 2 2 \frac{x^4}{2^2} 22x4 |
3 3 3 | ( ( x 4 2 2 ) 2 ) 2 \left(\frac{\left(\frac{x^4}{2^2}\right)}{2}\right)^2 (2(22x4))2 | x 8 2 6 \frac{x^8}{2^6} 26x8 |
4 4 4 | ( ( x 8 2 6 ) 2 ) 2 \left(\frac{\left(\frac{x^8}{2^6}\right)}{2}\right)^2 (2(26x8))2 | x 16 2 14 \frac{x^{16}}{2^{14}} 214x16 |
观察上面的格式特征,我们不妨记经过第 i i i 次变换后得到的结果为 x m 2 n \frac{x^m}{2^n} 2nxm。对 m , n m,n m,n 分别进行分析,如下所示:
i i i | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | … … …… …… | k k k |
---|---|---|---|---|---|---|---|
m m m | 2 2 2 | 4 4 4 | 8 8 8 | 16 16 16 | 32 32 32 | … … …… …… | 2 k 2^k 2k |
n n n | 0 0 0 | 2 2 2 | 6 6 6 | 14 14 14 | 30 30 30 | … … …… …… | 2 k − 2 2^k-2 2k−2 |
通过上表,我们可以得到结果的一个通用表达式。记经过第 i i i 次变换后的结果为 x i x_i xi,则有:
x i = x 2 i 2 2 i − 2 x_i=\frac{x^{2^i}}{2^{2^i-2}} xi=22i−2x2i
题目分析
截至目前,我们已经得出了对于题目给定的变换方法的通式:
x i = x 2 i 2 2 i − 2 x_i=\frac{x^{2^i}}{2^{2^i-2}} xi=22i−2x2i
由于题目要求的是一个最小的正整数 k k k,使得经过 k k k 次变换后得到的答案大于 2 n 2^n 2n,于是就会有下面的不等式:
x 2 k 2 2 k − 2 ≥ 2 n \frac{x^{2^k}}{2^{2^k-2}} \geq 2^n 22k−2x2k≥2n
这时,我想到了高中数学中的对数,其中有一条定理:
对于一个不等式 m ≥ n m \geq n m≥n,将其两边同时取以同一数字为底的对数之后,不等号方向不变,即满足 log k m ≥ log k n \log_k{m} \geq \log_k{n} logkm≥logkn。
上述结论可以利用对数函数的单调性证明,在这里不过多阐述。所以对于这道题,由代数知识可有如下推导过程,应该是足够详细了:
x 2 k 2 2 k − 2 ≥ 2 n \frac{x^{2^k}}{2^{2^k-2}} \geq 2^n 22k−2x2k≥2n
x 2 k ≥ 2 n × 2 2 k − 2 x^{2^k} \geq 2^n \times {2^{2^k-2}} x2k≥2n×22k−2
x 2 k ≥ 2 n + 2 k − 2 x^{2^k} \geq 2^{n+2^k-2} x2k≥2n+2k−2
l o g 2 x 2 k ≥ l o g 2 2 n + 2 k − 2 log_2{x^{2^k} }\geq log_2{2^{n+2^k-2}} log2x2k≥log22n+2k−2
2 k l o g 2 x ≥ ( n + 2 k − 2 ) × l o g 2 2 2^klog_2{x}\geq (n+2^k-2) \times log_2{2} 2klog2x≥(n+2k−2)×log22
2 k l o g 2 x ≥ n + 2 k − 2 2^k log_2{x}\geq n+2^k-2 2klog2x≥n+2k−2
2 k l o g 2 x − 2 k ≥ n − 2 2^k log_2{x} - 2^k \geq n - 2 2klog2x−2k≥n−2
2 k ≥ n − 2 l o g 2 x − 1 2^k \geq \frac{n-2}{ log_2{x} -1} 2k≥log2x−1n−2
k ≥ l o g 2 n − 2 l o g 2 x − 1 k \geq log_2{\frac{n-2}{ log_2{x} -1}} k≥log2log2x−1n−2
看到这里,终于是拨开云雾了。经过我们的推导,发现对于给定的
x
,
n
x,n
x,n,在一般情况下,程序只要输出一个
⌈
l
o
g
2
n
−
2
l
o
g
2
x
−
1
⌉
\lceil log_2{\frac{n-2}{ log_2{x} -1}} \rceil
⌈log2log2x−1n−2⌉ 即可。
参考代码
#include<bits/stdc++.h>
using namespace std;
int x, n;
int main() {
cin >> x >> n;
if(x==2&&n==2){
cout<<1<<endl;
return 0;
}
if (x == 2 && n > 2) {
cout << "inf" << endl;
return 0;
}
if (x >= pow(2, n)) {
cout << 0 << endl;
return 0;
}
if (log2((n - 2) / (log2(x) - 1))< 0) {
cout << "inf" << endl;
return 0;
}
cout << ceil(log2((n - 2) / (log2(x) - 1))) << endl;
return 0;
}
这道题特判特别多,所以很考验我们对细节的理解,选手们要多加注意。