题目:
- 本题一开始不太有思路,参照了各个题解和分析,学到了一些东西,记录一下。
描述
N<k时,root(N,k) = N,否则,root(N,k) = root(N',k)。
N'为N的k进制表示的各位数字之和。
输入x,y,k,输出root(x^y,k)的值
(这里^为乘方,不是异或),
2=<k<=16,0<x,y<2000000000,
有一半的测试点里 x^y 会溢出int的范围(>=2000000000)
输入描述:
每组测试数据包括一行,x(0<x<2000000000), y(0<y<2000000000), k(2<=k<=16)
输出描述:
输入可能有多组数据,对于每一组数据,root(x^y, k)的值
示例1:
|输入: 4 4 10
|输出: 4
需要补充的数学理论知识
- 数根: 整数的各个数位数字之和具有什么意义?相等意味着什么
- 模的运算法则
- 快速幂
有了上述的理解基础,那么这道题就有了理解的基础
关键
-
- 首先本题幂次较高,很容易超出int 表示范围,求快速幂的时候最好用 long long;
-
- 但实际上,在求快速幂的过程中,利用模的运算法则,和数根的理论,一边求幂一边取模,进而减小参与运算的数值大小,减小溢出的可能性,适合于这道题解法。
-
- 即由(xy)%p=(x%py%p)%p,((ab)%pc)%p=(a(ba)%p)%p;
- 那么(xx)%p=(x%px%p)%p;
- 所以在求幂次之前,先取模再乘上幂次取模结果不影响。
#include <iostream>
using namespace std;
//root(N,k)=N%(k-1)
int fastExp(int x, int y, int k) {
int answer = 1;
while (y != 0) {
if (y % 2 != 0) {
answer *= x;
answer %= (k - 1);\\直接先求模,减小数值范围
}
x %= (k - 1);\\先求模减小数值范围
x *= x;
// 注意,如果先乘再取模要用long long
// 要不然x*x会超过int范围
y >>= 1;
}
return answer;
}
int main() {
int x, y, k;
cin >> x >> y >> k;
int m = fastExp(x, y, k);
\\注意 这个快速幂里保证了每一步都求模,即保证了对原数k进制转换。
if (m == 0) {\\对取模为0的处理,实际上余数为k-1;
m += k - 1;
}
cout << m;
}