传送门:洛谷 P1050
题目描述
乐乐是一个聪明而又勤奋好学的孩子。他总喜欢探求事物的规律。一天,他突然对数的正整数次幂产生了兴趣。
众所周知,
2
2
2的正整数次幂最后一位数总是不断的在重复
2
,
4
,
8
,
6
,
2
,
4
,
8
,
6
…
2,4,8,6,2,4,8,6…
2,4,8,6,2,4,8,6…我们说
2
2
2的正整数次幂最后一位的循环长度是
4
4
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}
n23456789循环2,4,8,63,9,7,14,6567,9,3,18,4,2,69,1循环长度44211442
这时乐乐的问题就出来了:是不是只有最后一位才有这样的循环呢?对于一个整数nn的正整数次幂来说,它的后k位是否会发生循环?如果循环的话,循环长度是多少呢?
注意:
1. 如果
n
n
n的某个正整数次幂的位数不足k,那么不足的高位看做是
0
0
0。
2. 如果循环长度是
L
L
L,那么说明对于任意的正整数
a
,
n
a,n
a,n的
a
a
a次幂和
a
+
L
a+L
a+L次幂的最后
k
k
k位都相同。
分析
一道头痛的凶残的数学题,首先看看数据范围,有点头痛(就不能好好地打打暴力么),加上高精度也绝对是要T了的。
对此考虑用数学来补救
在保证有解的情况下,若后
x
x
x位的循环长度为
y
y
y,则后
x
+
1
x+1
x+1位的长度必定为
k
×
y
k \times y
k×y,其中
k
∈
N
∗
k \in N^*
k∈N∗.因此,我们可以考虑从个位数开始逐步往前递推,每次只需求出对应的
k
k
k即可。
寻找
k
k
k:令原数为
n
n
n,若寻找后
x
+
1
x+1
x+1的长度,我们只需要找到最小的
k
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≡n×ny×k(mod10x+1),对此,先求出
n
y
n^y
ny,然后枚举k判断即可
判断有解:经证明(/逃,知道的
d
a
l
a
o
dalao
dalao,请留个言,谢谢),
k
≤
10
k \leq 10
k≤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--] - '0'];
power(ans.num[1]);
for(int i = 2; i <= m; ++i)
{
++(p.size);
if(len) p.num[p.size] = num[len--] - '0';
check(p, i);
if(ans.num[1] == -1) break;
}
ans.wri();
//close
return 0;
}