1. 程式人生 > >[洛谷 P1050] 迴圈 -- 數學 + 高精度

[洛谷 P1050] 迴圈 -- 數學 + 高精度

傳送門:洛谷 P1050


題目描述

樂樂是一個聰明而又勤奮好學的孩子。他總喜歡探求事物的規律。一天,他突然對數的正整數次冪產生了興趣。

眾所周知, 2 2 的正整數次冪最後一位數總是不斷的在重複 2 , 4

, 8 , 6 , 2 , 4 , 8 ,
6 2,4,8,6,2,4,8,6… 我們說 2 2 的正整數次冪最後一位的迴圈長度是 4
4
(實際上 4 4 的倍數都可以說是迴圈長度,但我們只考慮最小的迴圈長度)。類似的,其餘的數字的正整數次冪最後一位數也有類似的迴圈現象:
n 迴圈 迴圈長度 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 \begin{array}{|c|c|c|} \hline n & \text{迴圈} & \text{迴圈長度} \\ \hline 2 & 2,4,8,6 & 4 \\ \hline 3 & 3,9,7,1 & 4\\ \hline 4 & 4,6 & 2\\ \hline 5 & 5 & 1\\ \hline 6 & 6 & 1\\ \hline 7 & 7,9,3,1 & 4\\ \hline 8 & 8,4,2,6 & 4\\ \hline 9 & 9,1 & 2\\ \hline \end{array}

這時樂樂的問題就出來了:是不是隻有最後一位才有這樣的迴圈呢?對於一個整數nn的正整數次冪來說,它的後k位是否會發生迴圈?如果迴圈的話,迴圈長度是多少呢?

注意:
1. 如果 n n 的某個正整數次冪的位數不足k,那麼不足的高位看做是 0 0
2. 如果迴圈長度是 L L ,那麼說明對於任意的正整數 a , n a,n a a 次冪和 a + L a+L 次冪的最後 k k 位都相同。


分析

一道頭痛的凶殘的數學題,首先看看資料範圍,有點頭痛(就不能好好地打打暴力麼),加上高精度也絕對是要T了的。
 對此考慮用數學來補救
 在保證有解的情況下,若後 x x 位的迴圈長度為 y y ,則後 x + 1 x+1 位的長度必定為 k × y k \times y ,其中 k N k \in N^* .因此,我們可以考慮從個位數開始逐步往前遞推,每次只需求出對應的 k k 即可
 尋找 k k :令原數為 n n ,若尋找後 x + 1 x+1 的長度,我們只需要找到最小的 k k ,使之滿足 n n × n y × k ( m o d    1 0 x + 1 ) n \equiv n \times n^{y \times k} (\mod 10^{x + 1}) ,對此,先求出 n y n^y ,然後列舉k判斷即可
 判斷有解:經證明(/逃,知道的 d a l a o dalao ,請留個言,謝謝), k 10 k \leq 10 ,超出範圍則無解


程式碼

#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--] - <