[NOIP2005] 普及组 循环
Posted SilverNebula
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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
说明
对于30%的数据,k <= 4;
对于全部的数据,k <= 100。
NOIP2005普及组第四题
依照题意累乘,设原数是n,假设乘了x次后,最后一位(第L位)的数与最开始相同了,那么就要开始计算倒数第二位(L-1位)的循环节。
由于L位至少要乘x次才能循环,所以算L-1位时,至少要乘n^x次才能让L位再重复(L-1位循环而L位不同是没有意义的)。
以此类推,每找到一层循环,在找下一层时就可以每次直接乘n^x^y^...,运行效率会高很多。
具体实现要用到高精度。
这代码估计是高精乘法常数写挂了,用时近1000ms
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdio> 5 using namespace std; 6 int t=1; 7 unsigned int n=0,k; 8 unsigned int xh[200]; 9 int num;//记录有多少层 10 char s[200]; 11 bool flag=0,flag2=0; 12 struct node{ 13 unsigned int v[200]; 14 int s; 15 }a,b,c,bas,ans,nn; 16 node multiple(const node a1,const node b1){ //高精度乘法部分 17 int i,j,x=0; 18 if(a1.s==1&&a1.v[0]==0)return a1; 19 if(b1.s==1&&b1.v[0]==0)return b1; 20 node c1={0}; 21 for(i=0;i<=100 && i<a1.s;i++){ 22 for(j=0;j<=100 && j<b1.s;j++){ 23 c1.v[i+j]+=a1.v[i]*b1.v[j]; 24 c1.v[i+j+1]+=c1.v[i+j]/10; 25 c1.v[i+j]%=10; 26 } 27 c1.s=i+j; 28 if(c1.v[i+j]!=0)c1.s++; 29 } 30 if(c1.s>k) c1.s=k+1; 31 return c1; 32 } 33 34 int main(){ 35 int i,j; 36 scanf("%s%d",s,&k); 37 c.s=strlen(s); 38 ans.v[0]=1; 39 ans.s=1; 40 for(i=0;i<c.s;i++) c.v[i]=s[c.s-i-1]-‘0‘; 41 bas=c;//原数备份,用作比较 42 a=c; 43 b=c; 44 int k1; 45 for(k1=0;k1<k;k1++){ 46 num=0; 47 b=bas; 48 // c=bas; 49 do{ 50 b=multiple(a,b); 51 num++; 52 }while(num<10 && b.v[k1]!=bas.v[k1]); 53 if(bas.v[k1]!=b.v[k1]){ 54 printf("-1"); 55 return 0; 56 } 57 b=a; 58 for(j=0;j<num-1;j++) 59 a=multiple(a,b); 60 61 nn.s=1; 62 nn.v[0]=num; 63 ans=multiple(ans,nn); 64 } 65 i=100; 66 while(ans.v[i]==0)i--; 67 for( ;i>=0;i--)printf("%d",ans.v[i]); 68 return 0; 69 }
以上是关于[NOIP2005] 普及组 循环的主要内容,如果未能解决你的问题,请参考以下文章
P1048 [NOIP2005 普及组] 采药(01背包 dp)