众所周知,2的正整数次幂最后一位数总是不断的在重复2,4,8,6,2,4,8,6……我们说2的正整数次幂最后一位的循环长度是4(实际上4的倍数都可以说是循环长度,但我们只考虑最小的循环长度)。类似的,其余的数字的正整数次幂最后一位数也有类似的循环现象:
数字 | 循环 | 循环长度 |
2 | 2、4、8、6 | 4 |
3 | 3、9、7、1 | 4 |
4 | 4、6 | 2 |
5 | 5 | 1 |
6 | 6 | 1 |
7 | 7、9、3、1 | 4 |
8 | 8、4、2、6 | 4 |
9 | 9、1 | 2 |
注意:
1. 如果n的某个正整数次幂的位数不足k,那么不足的高位看做是0。
2. 如果循环长度是L,那么说明对于任意的正整数a,n的a次幂和a + L次幂的最后k位都相同。
对于全部的数据,k <= 100。
解析:我直接举一个例子进行说明吧:111 3(由于1的循环长度就是1,所以我直接从末两位循环开始)
我们来看111的末两位循环:
111 -> 321 -> 631 -> 041 -> 551 -> 161 -> 871 -> 681 -> 591 -> 601 -> 711
711处末两位出现循环,循环长度为10,循环节为11-> ...-> 01
现在我们再来看末三位循环:
111->...->601 (10个数)
711->...->201 (201就是601^2的末三位)
311->...->801 (801就是601^3的末三位)
911->...->401 (401就是601^4的末三位)
511->...->001 (001就是601^5的末三位)
111->...->601 (601就是601^6的末三位)
末三位的循环长度就是5*10=50;
好了,现在来讲具体的做法,并假设我们现在求数字n的后k位循环。
朴素的做法就是直接求n^2,n^3,n^4.。。。,并判断是否出现循环。但观察上面的演示例子,我们发现可以不必这样,以n=111为例,末两位循环节长度为10,即表示n与(n^10)*n的末两位是相同的。对于末三位的循环,肯定是(m*n^10),即m*(n^10)与n^10的末三位是相同的,m*(n^10)*n的末三位与n相同。 于是,计算末三位循环的时候,我们就直接将n^10作为第一个数,然后每次乘n^10,共乘5次,末三位出现循环,即m=5,所以末三位循环街长度就为5*10=50。
代码:
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn=100;
int n,a[maxn+10],b[maxn+10];
int c[2][maxn+10],ans[maxn+10];
char s[maxn+10];
bool same(int p[],int q[],int x)
{
for(int i=1;i<=x;i++)if(p[i]!=q[i])return 0;
return 1;
}
void multi_1(int x)
{
int i,last=0;
for(i=1;i<=ans[0];i++)
{
ans[i]=ans[i]*x+last;
last=ans[i]/10,ans[i]%=10;
}
if(last>0)ans[++ans[0]]=last;
}
void multi_2(int w[],int p[],int q[])
{
int i,k,last=0;
w[0]=min(p[0]+q[0]-1,n);
for(k=1;k<=w[0];k++)
{
for(w[k]=last,i=1;i<=p[0];i++)
if(k+1-i>=1 && k+1-i<=q[0])w[k]+=p[i]*q[k+1-i];
last=w[k]/10,w[k]%=10;
}
if(last)w[++w[0]]=last;
}
int get(int x)
{
memcpy(c[0],b,sizeof(b));
for(int i=1;i<=10;i++)
{
multi_2(c[i%2],c[(i+1)%2],b);
if(same(c[i%2],b,x))
{
multi_2(c[i%2],c[(i-1)%2],a);
if(!same(c[i%2],a,x))goto d1;
memcpy(b,c[(i-1)%2],sizeof(c[0]));
return i;
}
}
d1:printf("-1\n");
exit(0);
}
int main()
{
int i; scanf("%s%d",s,&n);
a[0]=strlen(s),n=min(a[0],n);
for(i=1;i<=n;i++)a[i]=s[a[0]-i]-'0';
memcpy(b,a,sizeof(a)),ans[0]=1,ans[1]=1;
for(i=1;i<=n;i++)multi_1(get(i));
for(i=ans[0];i>=1;i--)printf("%d",ans[i]);
return 0;
}