题目描述
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)的值
示例:
输入
4 4 10
输出
4
分析
这道题乍一看好像没有什么思路,那就先暴力求解试试。不过不管你用pow函数,还是用快速幂运算,都过不了,因为结果已经爆long long int。有关快速幂运算这里简单提一下,不清楚的可以自行Google。
快速幂运算是用来计算形如xy这种式子的一种快速方法,核心在于将指数y表示为二进制的形式,并将计算拆分为x2n这种形式,这样在计算后一个指数运算时,可以利用前面的计算结果,减少了计算量,加快了运算速度。
这道题暴力解决不了,只能想其他方法,考虑到这可能是一个数学问题,如果我们能够找出其中的规律,就能迎刃而解。题目说N’是N的k进制数字之和,那么可以首先将N用k进制表示出来。
设a0,a1,…,an分别为kn的系数
那么N = a0 + a1k + a2k2 + … + ankn
根据题意N’ = a0 + a1 + … + an,两式相减
N - N’ = a1(k-1) + a2(k2-1) + … + an(kn-1),两边同时模k-1
N - N’ % (k-1) = 0,继续递推下去
N’ - N’’ % (k-1) = 0,
…
N(i-1) - N(i) % (k-1) = 0,进行累加
N - N(i) % (k-1) = 0,移项
N(i) = N % (k-1),N(i)即为我们所求值,N(i) < k
上面的推导过程使用了模运算的性质,如果有不清楚的地方,可以学习一下模运算。模运算在数学题中很常见,也需要掌握。
这样我们就得到了上面的公式,因为在运算过程中取模,所以不会爆int。另外还需要注意边界条件,N(i) = 0的情况下,实际应该输出k-1。因为如果xy不为0,那么结果一定不会为0。在实际编程中使用了快速模幂运算,其实就是在快速幂运算的基础上进行改进,在每一步的运算过程中都进行取模运算,这个算法也是需要掌握的。
AC代码如下:
#include<iostream>
using namespace std;
int func(long long int x, long long int y, int k)//快速模幂运算模板
{
int result = 1;
while(y > 0)
{
if(y&1)//取y二进制的最低位
{
result = (result*x) % k;
}
x = (x*x) % k;//每次需要增大基数
y >>= 1;//y右移一位,相当于除以2
}
return result;
}
int main(void)
{
int x, y, k;
while(cin >> x >> y >> k)
{
int result = func(x, y, k-1);//模为k-1
if(result == 0)//边界条件处理
{
cout << k-1;
}
else
{
cout << result;
}
}
return 0;
}