NOIP2005普及组第四题,
题目描述
乐乐是一个聪明而又勤奋好学的孩子。他总喜欢探求事物的规律。一天,他突然对数的正整数次幂产生了兴趣。
众所周知,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
这时乐乐的问题就出来了:是不是只有最后一位才有这样的循环呢?对于一个整数n的正整数次幂来说,它的后k位是否会发生循环?如果循环的话,循环长度是多少呢?
注意:
1. 如果n的某个正整数次幂的位数不足k,那么不足的高位看做是0。
2. 如果循环长度是L,那么说明对于任意的正整数a,n的a次幂和a + L次幂的最后k位都相同。
输入输出格式
输入格式:
输入文件circle.in只有一行,包含两个整数n(1 <= n < 10^100)和k(1 <= k <= 100),n和k之间用一个空格隔开,表示要求n的正整数次幂的最后k位的循环长度。
输出格式:
输出文件circle.out包括一行,这一行只包含一个整数,表示循环长度。如果循环不存在,输出-1。
输入输出样例
32 2
4
算法分析
可以发现,如果后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个数字中某个数开始的而不包括应该循环的那一位,那么意味着该循环的一位永远不会循环.那么这个时候就可以判断,这个数不会出现循环
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int k,kk;
struct date{
int x[10005];
friend void read(date&a){
char s[10005];
int i,j;
cin>>s;
for(i=0;s[i];i++);
for(i--,j=0;i>=0;i--,j++)a.x[j]=s[i]-'0';
}
date operator*(date&b){
date c;
for(int i=0;i<k;i++)for(int j=0;i+j<k;j++)
c.x[i+j]+=x[i]*b.x[j];
for(int i=0;i<k;i++){
c.x[i+1]+=c.x[i]/10;
c.x[i]%=10;
}
return c;
}
date operator*(int&b){
for(int i=0;i<k;i++)x[i]*=b;
for(int i=0;i<k;i++){
x[i+1]+=x[i]/10;
x[i]%=10;
}
return *this;
}
bool operator==(date&b){
for(int i=0;i<=kk;i++)if(x[i]!=b.x[i])return false;
return true;
}
date(){for(int i=0;i<=10005;i++)x[i]=0;}
}c,s,n,ans;
int main(){
int i;
read(n);
scanf("%d",&k);
// ans=s*n;
// for(i=k;i&&!ans.x[i];i--);
// for(i;i>=0;i--)printf("%d",ans.x[i]);
ans.x[0]=1;
for(kk=0;kk<k;kk++){
c=n;
for(i=1;;i++){
s=c*n;
if(s==n){n=c;ans=ans*i;break;}
c=s;
if(i>10){printf("-1");return 0;}
}
}
for(i=k;i>0&&!ans.x[i];i--);
for(i;i>=0;i--)printf("%d",ans.x[i]);
}