如何判断一个β位的整数n是否是某个整数的幂?

时间:2022-09-16 05:19:37
时间复杂度控制在关于β的多项式时间内。并且这个幂是大于1的,这个n也是大于1的。PS:我只求得了关于n的多项式时间的算法。哪位大神来帮忙提示下思路?当然有关键代码更好了。。 

12 个解决方案

#1


你首先要知道k次方根的多项式算法。
然后假设n=a^b,a和b分别从2试到logn就行。

#2


引用 1 楼 FancyMouse 的回复:
你首先要知道k次方根的多项式算法。
然后假设n=a^b,a和b分别从2试到logn就行。

貌似b可以从2试到logn。但是a是n的因子,这个因子能整除n可不仅仅是2到logn范围内的数,从2到根号n范围内的数都有希望整除n,例如n=30^3  取底数最低为2,logn最大只能到14,但是30才是答案。而根号30^3=164>30  所以在循环里可以取到30,但是如果这样 至少复杂度为O(根号n)=O(2^(β/2)),这不是一个关于β的多项式算法。

#3


引用 2 楼 z84616995z 的回复:
Quote: 引用 1 楼 FancyMouse 的回复:

你首先要知道k次方根的多项式算法。
然后假设n=a^b,a和b分别从2试到logn就行。

貌似b可以从2试到logn。但是a是n的因子,这个因子能整除n可不仅仅是2到logn范围内的数,从2到根号n范围内的数都有希望整除n,例如n=30^3  取底数最低为2,logn最大只能到14,但是30才是答案。而根号30^3=164>30  所以在循环里可以取到30,但是如果这样 至少复杂度为O(根号n)=O(2^(β/2)),这不是一个关于β的多项式算法。

试a的时候用取对数的方法看b是不是整数。试b的时候用开根的办法看a是不是整数。a和b至少有一个<=logn这是肯定的。

#4


引用 3 楼 FancyMouse 的回复:
Quote: 引用 2 楼 z84616995z 的回复:

Quote: 引用 1 楼 FancyMouse 的回复:

你首先要知道k次方根的多项式算法。
然后假设n=a^b,a和b分别从2试到logn就行。

貌似b可以从2试到logn。但是a是n的因子,这个因子能整除n可不仅仅是2到logn范围内的数,从2到根号n范围内的数都有希望整除n,例如n=30^3  取底数最低为2,logn最大只能到14,但是30才是答案。而根号30^3=164>30  所以在循环里可以取到30,但是如果这样 至少复杂度为O(根号n)=O(2^(β/2)),这不是一个关于β的多项式算法。

试a的时候用取对数的方法看b是不是整数。试b的时候用开根的办法看a是不是整数。a和b至少有一个<=logn这是肯定的。

大神!我又想了一遍,确实如您所说只要知道求k次方根的多项式算法就能解决这个问题。我想用编译器里面自带的库函数pow计算k次方根,然后从k=2到logn试探,您看行吗? 系统自带的pow函数时间复杂度在关于β的多项式时间内吗?感觉如果自己写个pow函数可能没系统给的好些并且也不太可能保证时间复杂度能在多项式时间内。

#5


关系统函数什么事……系统函数只能做编译器固有类型的。固有类型的那直接把答案枚举出来查表就行,还需要啥多项式……要关心多项式算法的,n位数你至少也要弄个几百上千吧。

#6


引用 5 楼 FancyMouse 的回复:
关系统函数什么事……系统函数只能做编译器固有类型的。固有类型的那直接把答案枚举出来查表就行,还需要啥多项式……要关心多项式算法的,n位数你至少也要弄个几百上千吧。

因为我不清楚怎么在多项式时间内计算泰勒公式或牛顿迭代法来求k次方根,所以我是想用编译器自带的pow函数求k次方根,所以我关心系统的pow函数的运行时间。而且现在连int整型范围内的数据都没搞清楚呢,所以暂时没有想计算几百位几千位的数据。
你看下面我的写的这个程序除了pow函数,其他都是自己写的。

#include <iostream>
#include <math.h>
using namespace std;
//位运算的除法
int Dev(int n,int i)//O(lgn)
{
int ans=0,bit=0;
while((n>>bit)>=1)bit++;//O(lgn)
for (int j=bit;j>=0;j--)//O(lgn)
{
if ((n>>j)>=i)
{
ans+=(1<<j);
n-=(i<<j);
}
}
return ans;
}
//求对数
int Log(int n,int i)//以i为底的n的对数
{//O(lgnlgn)=O(β^2)
int temp=0;
while (n>1)//O(lgn)
{
n=Dev(n,i);//O(lgn)
temp++;
}
return temp;
}
void main()
{
double n=31*31*31,flag=1;
int t=0;
for (int i=2;i<=Log(n,2)+1;i++)//O(lgn)
{
double p=fabs(pow(n,1.0/i)-(int)pow(n,1.0/i));
if (p>0.5) t=(int)pow(n,1.0/i)+1;//类似四舍五入
else t=pow(n,1.0/i);
if (pow(t,i)==n)
{
cout<<n<<"是非平凡幂,存在一个整数"<<pow(n,1.0/i)<<"它的"<<i<<"次幂="<<n<<endl;
flag=0;
//break;
}
}
if (flag)
{
cout<<"n="<<n<<"不存在非平凡幂"<<endl;
}
}

#7


int型就直接瞎搞了啊。

map<int,pair<int,int>> m;
for(int i=2;i<65536;i++)
{
  int c = i;
  for(int j=1;c<=INT_MAX/i;j++,c*=i)
    m[c] = make_pair(i,j);
}

然后直接查表……

#8


引用 7 楼 FancyMouse 的回复:
int型就直接瞎搞了啊。

map<int,pair<int,int>> m;
for(int i=2;i<65536;i++)
{
  int c = i;
  for(int j=1;c<=INT_MAX/i;j++,c*=i)
    m[c] = make_pair(i,j);
}

然后直接查表……

您这个不满足题目要求啊! 要满足关于β的多项式时间才行。

#9


引用 8 楼 z84616995z 的回复:
Quote: 引用 7 楼 FancyMouse 的回复:

int型就直接瞎搞了啊。

map<int,pair<int,int>> m;
for(int i=2;i<65536;i++)
{
  int c = i;
  for(int j=1;c<=INT_MAX/i;j++,c*=i)
    m[c] = make_pair(i,j);
}

然后直接查表……

您这个不满足题目要求啊! 要满足关于β的多项式时间才行。

我都说了 int的话这么瞎搞。又是只需要处理int又要关于长度多项式那是耍流氓。

#10


引用 9 楼 FancyMouse 的回复:
Quote: 引用 8 楼 z84616995z 的回复:

Quote: 引用 7 楼 FancyMouse 的回复:

int型就直接瞎搞了啊。

map<int,pair<int,int>> m;
for(int i=2;i<65536;i++)
{
  int c = i;
  for(int j=1;c<=INT_MAX/i;j++,c*=i)
    m[c] = make_pair(i,j);
}

然后直接查表……

您这个不满足题目要求啊! 要满足关于β的多项式时间才行。

我都说了 int的话这么瞎搞。又是只需要处理int又要关于长度多项式那是耍流氓。

我明白你的意思,如果数小的话,没必要。大整数才有意义。其实这是《算法导论》第31章出现的问题。原题看下面图。
如何判断一个β位的整数n是否是某个整数的幂?
您看这个问题是要求计算上百位上千位的数?说实话我编写的最大整数就是unsigned _int64 这么大,再大的数还没接触过,也不清楚用什么技术去解决,同时感觉用到超过20位整数的地方比较少,所以一直也没研究这种大整数的问题。感觉即使《算法导论》上也没有介绍如何求上百位上千位的这么大的整数。至少31章学完没看到。您推荐本介绍计算上百位上千位的书吧,我去看看。谢谢了!

#11


>您看这个问题是要求计算上百位上千位的数?
当然……int64就10位能满足这种题的胃口?

高精度有高精度自己的算法。CLRS上肯定提到过用分治和用FFT解决高精度乘法的章节的。

#12


引用 11 楼 FancyMouse 的回复:
>您看这个问题是要求计算上百位上千位的数?
当然……int64就10位能满足这种题的胃口?

高精度有高精度自己的算法。CLRS上肯定提到过用分治和用FFT解决高精度乘法的章节的。

感谢您给我的提示,分治法第2章就提到了,我是半年前学的,看来要复习下,FFT我没学过,网上查了是在第30章,这章没看呢,看来下面学习的目标要转向第30章了。这帖子就到此为止了。谢谢您给我指明了学习方向。

#1


你首先要知道k次方根的多项式算法。
然后假设n=a^b,a和b分别从2试到logn就行。

#2


引用 1 楼 FancyMouse 的回复:
你首先要知道k次方根的多项式算法。
然后假设n=a^b,a和b分别从2试到logn就行。

貌似b可以从2试到logn。但是a是n的因子,这个因子能整除n可不仅仅是2到logn范围内的数,从2到根号n范围内的数都有希望整除n,例如n=30^3  取底数最低为2,logn最大只能到14,但是30才是答案。而根号30^3=164>30  所以在循环里可以取到30,但是如果这样 至少复杂度为O(根号n)=O(2^(β/2)),这不是一个关于β的多项式算法。

#3


引用 2 楼 z84616995z 的回复:
Quote: 引用 1 楼 FancyMouse 的回复:

你首先要知道k次方根的多项式算法。
然后假设n=a^b,a和b分别从2试到logn就行。

貌似b可以从2试到logn。但是a是n的因子,这个因子能整除n可不仅仅是2到logn范围内的数,从2到根号n范围内的数都有希望整除n,例如n=30^3  取底数最低为2,logn最大只能到14,但是30才是答案。而根号30^3=164>30  所以在循环里可以取到30,但是如果这样 至少复杂度为O(根号n)=O(2^(β/2)),这不是一个关于β的多项式算法。

试a的时候用取对数的方法看b是不是整数。试b的时候用开根的办法看a是不是整数。a和b至少有一个<=logn这是肯定的。

#4


引用 3 楼 FancyMouse 的回复:
Quote: 引用 2 楼 z84616995z 的回复:

Quote: 引用 1 楼 FancyMouse 的回复:

你首先要知道k次方根的多项式算法。
然后假设n=a^b,a和b分别从2试到logn就行。

貌似b可以从2试到logn。但是a是n的因子,这个因子能整除n可不仅仅是2到logn范围内的数,从2到根号n范围内的数都有希望整除n,例如n=30^3  取底数最低为2,logn最大只能到14,但是30才是答案。而根号30^3=164>30  所以在循环里可以取到30,但是如果这样 至少复杂度为O(根号n)=O(2^(β/2)),这不是一个关于β的多项式算法。

试a的时候用取对数的方法看b是不是整数。试b的时候用开根的办法看a是不是整数。a和b至少有一个<=logn这是肯定的。

大神!我又想了一遍,确实如您所说只要知道求k次方根的多项式算法就能解决这个问题。我想用编译器里面自带的库函数pow计算k次方根,然后从k=2到logn试探,您看行吗? 系统自带的pow函数时间复杂度在关于β的多项式时间内吗?感觉如果自己写个pow函数可能没系统给的好些并且也不太可能保证时间复杂度能在多项式时间内。

#5


关系统函数什么事……系统函数只能做编译器固有类型的。固有类型的那直接把答案枚举出来查表就行,还需要啥多项式……要关心多项式算法的,n位数你至少也要弄个几百上千吧。

#6


引用 5 楼 FancyMouse 的回复:
关系统函数什么事……系统函数只能做编译器固有类型的。固有类型的那直接把答案枚举出来查表就行,还需要啥多项式……要关心多项式算法的,n位数你至少也要弄个几百上千吧。

因为我不清楚怎么在多项式时间内计算泰勒公式或牛顿迭代法来求k次方根,所以我是想用编译器自带的pow函数求k次方根,所以我关心系统的pow函数的运行时间。而且现在连int整型范围内的数据都没搞清楚呢,所以暂时没有想计算几百位几千位的数据。
你看下面我的写的这个程序除了pow函数,其他都是自己写的。

#include <iostream>
#include <math.h>
using namespace std;
//位运算的除法
int Dev(int n,int i)//O(lgn)
{
int ans=0,bit=0;
while((n>>bit)>=1)bit++;//O(lgn)
for (int j=bit;j>=0;j--)//O(lgn)
{
if ((n>>j)>=i)
{
ans+=(1<<j);
n-=(i<<j);
}
}
return ans;
}
//求对数
int Log(int n,int i)//以i为底的n的对数
{//O(lgnlgn)=O(β^2)
int temp=0;
while (n>1)//O(lgn)
{
n=Dev(n,i);//O(lgn)
temp++;
}
return temp;
}
void main()
{
double n=31*31*31,flag=1;
int t=0;
for (int i=2;i<=Log(n,2)+1;i++)//O(lgn)
{
double p=fabs(pow(n,1.0/i)-(int)pow(n,1.0/i));
if (p>0.5) t=(int)pow(n,1.0/i)+1;//类似四舍五入
else t=pow(n,1.0/i);
if (pow(t,i)==n)
{
cout<<n<<"是非平凡幂,存在一个整数"<<pow(n,1.0/i)<<"它的"<<i<<"次幂="<<n<<endl;
flag=0;
//break;
}
}
if (flag)
{
cout<<"n="<<n<<"不存在非平凡幂"<<endl;
}
}

#7


int型就直接瞎搞了啊。

map<int,pair<int,int>> m;
for(int i=2;i<65536;i++)
{
  int c = i;
  for(int j=1;c<=INT_MAX/i;j++,c*=i)
    m[c] = make_pair(i,j);
}

然后直接查表……

#8


引用 7 楼 FancyMouse 的回复:
int型就直接瞎搞了啊。

map<int,pair<int,int>> m;
for(int i=2;i<65536;i++)
{
  int c = i;
  for(int j=1;c<=INT_MAX/i;j++,c*=i)
    m[c] = make_pair(i,j);
}

然后直接查表……

您这个不满足题目要求啊! 要满足关于β的多项式时间才行。

#9


引用 8 楼 z84616995z 的回复:
Quote: 引用 7 楼 FancyMouse 的回复:

int型就直接瞎搞了啊。

map<int,pair<int,int>> m;
for(int i=2;i<65536;i++)
{
  int c = i;
  for(int j=1;c<=INT_MAX/i;j++,c*=i)
    m[c] = make_pair(i,j);
}

然后直接查表……

您这个不满足题目要求啊! 要满足关于β的多项式时间才行。

我都说了 int的话这么瞎搞。又是只需要处理int又要关于长度多项式那是耍流氓。

#10


引用 9 楼 FancyMouse 的回复:
Quote: 引用 8 楼 z84616995z 的回复:

Quote: 引用 7 楼 FancyMouse 的回复:

int型就直接瞎搞了啊。

map<int,pair<int,int>> m;
for(int i=2;i<65536;i++)
{
  int c = i;
  for(int j=1;c<=INT_MAX/i;j++,c*=i)
    m[c] = make_pair(i,j);
}

然后直接查表……

您这个不满足题目要求啊! 要满足关于β的多项式时间才行。

我都说了 int的话这么瞎搞。又是只需要处理int又要关于长度多项式那是耍流氓。

我明白你的意思,如果数小的话,没必要。大整数才有意义。其实这是《算法导论》第31章出现的问题。原题看下面图。
如何判断一个β位的整数n是否是某个整数的幂?
您看这个问题是要求计算上百位上千位的数?说实话我编写的最大整数就是unsigned _int64 这么大,再大的数还没接触过,也不清楚用什么技术去解决,同时感觉用到超过20位整数的地方比较少,所以一直也没研究这种大整数的问题。感觉即使《算法导论》上也没有介绍如何求上百位上千位的这么大的整数。至少31章学完没看到。您推荐本介绍计算上百位上千位的书吧,我去看看。谢谢了!

#11


>您看这个问题是要求计算上百位上千位的数?
当然……int64就10位能满足这种题的胃口?

高精度有高精度自己的算法。CLRS上肯定提到过用分治和用FFT解决高精度乘法的章节的。

#12


引用 11 楼 FancyMouse 的回复:
>您看这个问题是要求计算上百位上千位的数?
当然……int64就10位能满足这种题的胃口?

高精度有高精度自己的算法。CLRS上肯定提到过用分治和用FFT解决高精度乘法的章节的。

感谢您给我的提示,分治法第2章就提到了,我是半年前学的,看来要复习下,FFT我没学过,网上查了是在第30章,这章没看呢,看来下面学习的目标要转向第30章了。这帖子就到此为止了。谢谢您给我指明了学习方向。