[洛谷 P1050] 迴圈 -- 數學 + 高精度
阿新 • • 發佈:2018-11-10
傳送門:洛谷 P1050
題目描述
樂樂是一個聰明而又勤奮好學的孩子。他總喜歡探求事物的規律。一天,他突然對數的正整數次冪產生了興趣。
眾所周知,
的正整數次冪最後一位數總是不斷的在重複
我們說
的正整數次冪最後一位的迴圈長度是
(實際上
的倍數都可以說是迴圈長度,但我們只考慮最小的迴圈長度)。類似的,其餘的數字的正整數次冪最後一位數也有類似的迴圈現象:
這時樂樂的問題就出來了:是不是隻有最後一位才有這樣的迴圈呢?對於一個整數nn的正整數次冪來說,它的後k位是否會發生迴圈?如果迴圈的話,迴圈長度是多少呢?
注意:
1. 如果
的某個正整數次冪的位數不足k,那麼不足的高位看做是
。
2. 如果迴圈長度是
,那麼說明對於任意的正整數
的
次冪和
次冪的最後
位都相同。
分析
一道頭痛的凶殘的數學題,首先看看資料範圍,有點頭痛(就不能好好地打打暴力麼),加上高精度也絕對是要T了的。
對此考慮用數學來補救
在保證有解的情況下,若後
位的迴圈長度為
,則後
位的長度必定為
,其中
.因此,我們可以考慮從個位數開始逐步往前遞推,每次只需求出對應的
即可。
尋找
:令原數為
,若尋找後
的長度,我們只需要找到最小的
,使之滿足
,對此,先求出
,然後列舉k判斷即可
判斷有解:經證明(/逃,知道的
,請留個言,謝謝),
,超出範圍則無解
程式碼
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define IL inline
//#define open(s) freopen(s".in","r",stdin); freopen(s".out","w",stdout);
//#define close fclose(stdin); fclose(stdout);
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
int m;
IL int min_(int x, int y) { return x < y ? x : y; }
IL int max_(int x, int y) { return x > y ? x : y; }
struct Bigint
{
int size;
int num[105];
IL Bigint()
{
size = 0;
memset(num, 0, sizeof(num));
}
Bigint operator * (const Bigint &b) //高精*高精,限制了位數
{
Bigint c;
for(int i = 1, p, r; i <= size; ++i)
{
p = i;
r = 0;
for(int j = 1; j <= b.size && p <= m; ++j, ++p)
{
r += c.num[p] + num[i] * b.num[j];
c.num[p] = r % 10;
r /= 10;
}
for(; p <= m && r; ++p, r /= 10)
{
r += c.num[p];
c.num[p] = r % 10;
}
}
c.size = min_(size + b.size, m);
for(; !c.num[c.size]; --(c.size));
return c;
}
Bigint operator * (const int b) //高精*單精,僅供ans使用
{
Bigint c;
int s = size, r = 0;
for(int i = 1; i <= size; ++i)
{
r += b * num[i];
c.num[i] = r % 10;
r /= 10;
}
for(; r; r /= 10)
c.num[++s] = r % 10;
c.size = s;
return c;
}
IL bool is_same(int t, const Bigint &b)//判斷後t位相等
{
for(int i = min_(t, max_(size, b.size)); i; --i)
if(num[i] != b.num[i])
return 0;
return 1;
}
IL void wri()
{
for(int i = size; i; --i)
printf("%d", num[i]);
printf("\n");
}
}k, ans;
char num[105];
int base[10] = {0, 1, 4, 4, 2, 1, 1, 4, 4, 2};//預處理個位情況
IL void power(int t)//好吧,簡單的迴圈而已
{
if(t == 1) return ;
Bigint tmp = k;
for(--t; t; --t) k = k * tmp;
}
IL void check(Bigint p, int len)//求後len位的解
{
Bigint x = p;
for(int t = 1; t <= 10; ++t)
{
x = x * k;
if(p.is_same(len, x))
{
ans = ans * t;
power(t);
return ;
}
}
ans.size = 1;
ans.num[1] = -1;
}
int main()
{
//open("circle")
scanf(" %s %d", num + 1, &m);
int len = strlen(num + 1);
k.size = m < len ? m : len;
for(int i = 1; i <= k.size; ++i)
k.num[i] = num[len - i + 1] - '0';
Bigint p;
p.size = 1; p.num[1] = num[len] - '0';
ans.size = 1; ans.num[1] = base[num[len--] - <