NOIP2005普及組第4題 迴圈(高精度)
題目描述
樂樂是一個聰明而又勤奮好學的孩子。他總喜歡探求事物的規律。一天,他突然對數的正整數次冪產生了興趣。
眾所周知,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位都相同。
輸入
只有一行,包含兩個整數n(1 <= n < 10100)和k(1 <= k <= 100),n和k之間用一個空格隔開,表示要求n的正整數次冪的最後k位的迴圈長度。
輸出
包括一行,這一行只包含一個整數,表示迴圈長度。如果迴圈不存在,輸出-1。
【資料規模】
對於30%的資料,k <= 4;
對於全部的資料,k <= 100。
樣例輸入
32 2
樣例輸出
4
設後i位的迴圈節長度為 loop[i]
可以知道 loop[i] = x*loop[i-1],其中x為正整數且i>1,每次判斷只用判斷第i位是否與最初相同即可
就可以從後往前逐個遞推上去
判斷是否有迴圈,只需要標記一下求的那一位出現的數字,如果有一個不是最初的數字先出現了兩次則不可能有迴圈
如一個數a,先求出第一位數的迴圈長度為k,然後求第二位時每次就乘以a^k
a * a^k * a^k .. 直到第二位出現相同數字a^k 乘了p次,此時迴圈長度為 k*p,然後更新a^k到(a^k)^p 減少一點時間,不過直接算k*p次應該也可以吧。
最後的答案也是一個大數,longlong存不下,因為這個一直wa
#include <iostream> #include <stdio.h> #include <string.h> using namespace std; typedef long long LL; const int N = 1e2 + 10; char s[N]; int k,cnt; LL ans; struct node{ int num[N],len; node(){ memset(num,0,sizeof num); len = 1; } node friend operator * (node a,node b){ //運算子過載,大數乘法 node c; for(int i=1;i<=a.len;i++){ for(int j=1;j<=b.len;j++){ int pos = i+j-1,add = 0; if(pos>k) break; c.num[pos] += a.num[i] * b.num[j]; add = c.num[pos]/10; c.num[pos] %= 10; while(add>0&&pos<=k){ pos++; c.num[pos] += add; add = c.num[pos]/10; c.num[pos] %= 10; } if(pos>c.len) c.len = pos; } } return c; } }a,st; int flag = 0; int slove(int x,node now){//求第x位迴圈長度,now為當前要乘上的基數 int cnt = 1; node tem = st * now; int vis[15]; memset(vis,0,sizeof vis); while(tem.num[x]!=st.num[x]){ if(vis[tem.num[x]]) return 0;//如果先兩次出現了別的數字,則不存在迴圈 vis[tem.num[x]] = 1; tem = tem * now; cnt++; } return cnt; } int main() { scanf("%s%d",s,&k); node ans; ans.len = 1; ans.num[1] = 1; int len = strlen(s); for(int i=1;i<=k&&i<=len;i++) a.num[i] = s[len-i]-'0'; a.len = min(k, len); st = a; int flag = 0; for(int i=1;i<=k;i++){ int mul = slove(i, a); if(mul==0){ flag = 1; break; } node tem = a; for(int j=1;j<mul;j++) tem = tem * a;//得到新的要乘的基數 a = tem; tem.len = 0; while(mul){ tem.num[++tem.len] = mul % 10; mul /= 10; } ans = ans * tem;//更新當前位迴圈所需的最短迴圈長度 } if(flag) printf("-1\n"); else { for(int i=ans.len;i>=1;i--){ printf("%d",ans.num[i]); } printf("\n"); } return 0; }