算法分析:
直接枚举:用高精度乘法计算n的a次方,直到后k位出现循环,这样做有2个缺点:(1)时间复杂度过大,a的大小无法判断,可能会很超过MAXLONGINT,所以会超时 (2)无法判断不出现循环的情况
2.(1)可以发现,如果后k位循环,那么循环节一定是后k-1位循环的循环节的倍数
证明如下:设后k位循环节为a1,后k-1位循环的循环节是a2,且a1=p*a2+b(p,b是常数)
那么n^1的后k-1位=n^a2的后k-1位
n^1的后k位=n^a1的后k位->n^1的后k-1位=n^a1的后k-1位
所以n^a2的后k-1位等于n^a1的后k-1位...................................[1]
因为b不是循环节,所以n^(p*a2)的后k-1位不等于n^(p*a2+b)的后k-1位
n^(p*a2)的后k-1位等于n^a2的后k-1位
所以n^a2的后k-1位不等于n^a1的后k-1位,这与[1]矛盾,
所以我们可以求出后k-1位的循环节,再将后k-1位的循环节作为乘数求后k位的循环节(若n^a后k-1位与n的后k-1位相等,那么n^(a-1)为求后k位时的乘数),这样可以保证所枚举到的数一定是后k-1为循环节的倍数,而且可以大大减少枚举的数量
可以通过记录后k位循环节长度是后k-1的循环节的多少倍来求循环节,这样,枚举的数就不需要用高精度,最后结果相乘时用高精度
(2)整数的每一位有10种可能,如果某个长度枚举10次仍然没有循环的话,根据抽屉原理,因为这10个数中有1个没取到(就是该循环的一位)那么就一定出现了重复,也就是产生循环,但这个循环是以这9个数字中某个数开始的而不包括应该循环的那一位,那么意味着该循环的一位永远不会循环.那么这个时候就可以判断,这个数不会出现循环
这样做,上面直接枚举的2个问题都可以有效解决,
优化:
因为高精度计算中,计算后k位只需要保存后k位乘积的结果,而k范围较小,在计算是若判断大于k位则跳出,这样,节约了一定时间,同时也可以节约空间(因为结果只需存k位).
如果10次中已经出现循环的数,则可以退出
我的代码,比较肥。。。汗了
#include<iostream>
using namespace std;

typedef long long hugeint;

#define Base 10
#define MaxLen 500


int k;


struct BigNum
{
int len;
int data[MaxLen];

BigNum() :len(0)
{}

BigNum(const BigNum& s) :len(s.len)
{
memcpy(this->data,s.data,len*sizeof(*data));
}

BigNum(int s) :len(0)
{
for(;s>0;s=s/Base)
data[len++]=s%Base;
}


BigNum & operator = (const BigNum& s)
{
this->len=s.len;
memcpy(this->data,s.data,len*sizeof(*data));
return *this;
}


int& operator [](int index)
{ return data[index]; }

int operator [](int index) const
{ return data[index]; }
};


BigNum operator + (const BigNum & a, const BigNum & b)
{
BigNum c;
int i,carry=0;
c.len=a.len>b.len?a.len:b.len;

for(i=0;i<c.len||carry>0;++i)
{
if(i<a.len) carry+=a[i];
if(i<b.len) carry+=b[i];
c[i]=carry%Base;
carry/=Base;
}
c.len=i;
return c;
}


BigNum operator - (const BigNum & a, const BigNum & b)
{
BigNum c;
int lend=0, i;
c.len=a.len;

for(i=0; i<a.len; ++i)
{
c[i]=a[i]-lend;
if(i<b.len) c[i]-=b[i];
if(c[i]<0) lend=1,c[i]+=Base;
else lend=0;
}
while(c.len>0&&c[c.len-1]==0) --c.len;
return c;
}


BigNum operator * (const BigNum & a, const int b)
{
int i;
if(b==0) return 0;
BigNum c;
hugeint carry=0;

for(i=0;i<a.len;++i)
{
carry+=hugeint(a[i])*b;
c[i]=carry%Base;
carry/=Base;
}

for(;carry>0;++i)
{
c[i]=carry%Base;
carry/=Base;
}
c.len=i;
return c;
}


BigNum operator * (const BigNum & a, const BigNum & b)
{
int i,j;
if(b.len==0) return 0;
BigNum c;
hugeint carry;

for(i=0;i<a.len;++i)
{
carry=0;

for(j=0;j<b.len||carry>0;++j)
{
if(j<b.len) carry+=hugeint(a[i])*b[j];
if(i+j<c.len) carry+=c[i+j];
if((i+j)>=k) break;
if(i+j==c.len) c[c.len++]=carry%Base;
else c[i+j]=carry%Base;
carry/=Base;
}
}
return c;
}


BigNum operator / (const BigNum & a, const int b)
{
int i;
hugeint r=0;
BigNum c;

for(i=c.len-1;i>-1;--i)
{
r=r*Base+a[i];
c[i]=r/b;
r%=b;
}
c.len=a.len;
while(c.len>0&&c[c.len-1]==0) --c.len;
return c;
}


int compare(const BigNum & a, const BigNum & b)
{
int i;
if(a.len!=b.len) return a.len>b.len?1:-1;
for(i=a.len-1;i>-1&&a[i]==b[i];--i) ;
if(i==-1) return 0;
else return a[i]>b[i]?1:-1;
}


BigNum operator / (const BigNum & a, const BigNum & b)
{
int i;
BigNum c,carry=0;
int left,right,mid;

for(i=a.len-1;i>-1;--i)
{
carry=carry*Base+a[i];
left=0;
right=Base-1;

while(left<right)
{
mid=(left+right+1)/2;
if(compare(b*mid,carry)<=0)
left=mid;
else
right=mid-1;
}
c[i]=left;
carry=carry-b*left;
}
c.len=a.len;
while(c.len>0&&c[c.len-1]==0) --c.len;
return c;
}


BigNum operator % (const BigNum & a, const BigNum & b)
{
int i;
BigNum c,carry=0;
int left,mid,right;

for(i=a.len-1;i>-1;--i)
{
carry=carry*Base+a[i];
left=0;
right=Base-1;

while(left<right)
{
mid=(left+right+1)/2;
if(compare(b*mid,carry)<=0)
left=mid;
else
right=mid-1;
}
c[i]=left;
carry=carry-b*left;
}
c.len=a.len;
while(c.len>0&&c[c.len-1]==0) --c.len;
return carry;
}
istream & operator >> (istream & is, BigNum & s)


{
char ch;

for(s=0;is>>ch;)
{
s=s*10+(ch-'0');
if(cin.peek()<=' ')
break;
}
return is;
}

ostream & operator << (ostream & os, const BigNum & s)


{
int i,j;
os<<(s.len==0?0:s[s.len-1]);
for(i=s.len-2;i>-1;--i)
for(j=Base/10;j>0;j/=10)
os<<s[i]/j%10;
return os;
}


BigNum gcd(BigNum a, BigNum b)
{
if(b.len==0)
return a;
else
return gcd(b,a%b);
}



int main ()
{
BigNum n,num,step,mod,x;
int i,j,t,c[1001],flag;

while(cin>>n>>k)
{
if(compare(n,0)==0&&k==0)
break;
for(i=0;i<k;++i)
mod[i]=0;
t=-1;
mod[k]=1;
mod.len=k+1;
n=n%mod;
step=1;
x=n;

for(i=0;i<k;++i)
{
num=n;
step=x;
x=1;
flag=0;

for(j=0;j<10;++j)
{
num=num*step;
x=x*step;

if(num[i]==n[i])
{
flag=1;
c[++t]=j+1;
break;
}
}
if(flag!=1)
break;
}

if(flag!=1)
{
printf("-1\n");
continue;
}
for(i=0,x=1;i<=t;++i)
x=x*c[i];
cout<<x<<endl;
}
return 0;
}
