2.求root(N,k)

2.求root(N,k)

 

题目描述

    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)的值

https://www.nowcoder.com/questionTerminal/9324a1458c564c4b9c4bfc3867a2aa66?f=discussion
 

这题是2010年清华考研的机试题。关于此题,网上最常见的解法是通过一些数学推导得到result = N % (k - 1) 的结论,然后用快速幂取模算法求得答案。然而,如果我们将要求的结果写成root(x, y, k)的话,其实本题还可以直接用二分递归的方法求出root(x, y, k)。也就是说,题目要我们先对x乘方,再求root函数,但实际上我们可以先求root函数,再乘方(如果结果超过k的话还要再求root函数),那么为什么可以这样做呢?

对于root(N, k)中的N,我们可以把N看作关于k的多项式,也就是N = a0 + a1*k + a2*k^2 + … + an* k^n,而我们要求的root函数就是这个多项式的系数和,也就是a0 + a1 + a2 + ... + an。下面我们考虑root(N^2, k)。此时N^2 = (a0 + a1*k + a2*k^2 + … + an* k^n)^2,而这个多项式展开后的系数和是(a0 + a1 + a2 + … + an)^2,这个结果刚好就是先对N取root函数再平方的结果。实际上,我们很容易就能看出,多项式先乘方再取系数和(先乘再去掉k)与先取系数和再乘方(先去掉k再乘),结果是一样的(因为有没有k并不影响系数间的相乘,也不影响相乘之后的求和),于是乎,我们可以得到以下的递推公式:

root(x, y, k) = root((root(x, y / 2, k))^2, 1, k), y为偶数

root(x, y, k) = root((root(x, y / 2, k))^2 * root(x, 1, k), 1, k), y为非1的奇数

root(x, 1, k) = x % k + x / k % k + ...(大于k的话再重复求root)

有了递推关系之后,我们就可以直接写出一个O(log n)的递归解法了。

#include<iostream>
using namespace std;

int root(int x,int y,int k){
   if(y==1){
       if(x<k)
           return x;
       while(x>=k){
           int res=0;
           while(x){
               res+=x%k;
               x/=k;
           }
           x=res;
       }
       return x;
   }
    if(y%2==1){
        return root(root(x,y/2,k)*root(x,y/2,k)*root(x,1,k),1,k);
        
    }
    else return root(root(x,y/2,k)*root(x,y/2,k),1,k);
}

int main(){
    int x,y,k;
    while(cin>>x>>y>>k){
        cout<<root(x,y,k)<<endl;
    }
    return 0;
}
发布了49 篇原创文章 · 获赞 11 · 访问量 7631

猜你喜欢

转载自blog.csdn.net/mid_Faker/article/details/104355941
今日推荐