题意
传送门 POJ 3696
题解
8
…
8
=
8
×
1
…
1
=
8
×
(
1
0
x
−
1
)
/
9
8\dots8=8\times 1\dots 1=8\times (10^x-1)/9
8…8=8×1…1=8×(10x−1)/9,目标是求解满足下式的最小
x
x
x
8
(
1
0
x
−
1
)
9
m
o
d
L
=
0
\frac{8(10^x-1)}{9}\ mod\ L=0
98(10x−1) mod L=0 对于分母
9
9
9,从约数的角度考虑,将其合并进模数;对于分子
8
8
8,设
d
=
g
c
d
(
8
,
L
)
d=gcd(8,L)
d=gcd(8,L),考虑将分子
8
8
8 与模数同除以
d
d
d,此时
g
c
d
(
8
/
d
,
L
/
d
)
=
1
gcd(8/d,L/d)=1
gcd(8/d,L/d)=1,而
(
L
/
d
)
∣
(
8
/
d
)
×
(
1
0
x
−
1
)
/
9
(L/d)\ | \ (8/d)\times(10^x-1)/9
(L/d) ∣ (8/d)×(10x−1)/9,则有
(
L
/
d
)
∣
(
1
0
x
−
1
)
/
9
(L/d)\ | \ (10^x-1)/9
(L/d) ∣ (10x−1)/9,那么约束方程化为
1
0
x
=
1
m
o
d
9
L
d
10^x\ =\ 1\ mod\ \frac{9L}{d}
10x = 1 mod d9L
引理:若正整数 a , n a,n a,n 互质,则满足 a x = 1 m o d n a^x=1\ mod\ n ax=1 mod n 的最小正整数是 ϕ ( n ) \phi(n) ϕ(n) 的约数。
上述引理可以根据余数小于模数的性质用反证法证明。在上述引理中,假设 a , n a,n a,n 不互质,则有 g c d ( a , n ) > 1 gcd(a,n)>1 gcd(a,n)>1,对 a a a 求指数时,它与 n n n 的最大公因子不会变小,即 g c d ( a x , n ) > 1 gcd(a^x,n)>1 gcd(ax,n)>1,根据蜚蜀定理,方程无解。
观察到 1 0 x 10^x 10x 只有质因子 2 , 5 2,5 2,5 无法约去 9 L / d 9L/d 9L/d 中的质因子 3 3 3,故满足 1 0 x , 9 L / d 10^x,9L/d 10x,9L/d 互质。那么从小到大枚举欧拉函数的约数,快速幂进行判断是否满足条即可。总的时间复杂度为 O ( L l o g L ) O(\sqrt L logL) O(LlogL)。考虑到模数较大,直接做乘法会有 l o n g l o n g long \ long long long 溢出的风险,考虑快速乘或者平方分割乘数的方法即可,单次乘法复杂度分别为 O ( l o g n ) O(logn) O(logn) 与 O ( 1 ) O(1) O(1)。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
#define maxqt 100000
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
ll mod_mul(ll x, ll y, ll mod)
{
ll a = x / maxqt, b = x % maxqt;
a = (a * y) % mod, b = (b * y) % mod;
return ((a * maxqt) % mod + b) % mod;
}
ll mod_pow(ll x, ll n, ll mod)
{
ll res = 1;
while (n)
{
if (n & 1)
res = mod_mul(res, x, mod);
x = mod_mul(x, x, mod);
n >>= 1;
}
return res;
}
ll euler_phi(ll n)
{
ll res = n;
for (ll i = 2LL; i * i <= n; ++i)
{
if (n % i == 0)
{
res = res / i * (i - 1);
while (n % i == 0)
n /= i;
}
}
if (n > 1)
res = res / n * (n - 1);
return res;
}
int main()
{
ll L;
int c = 0;
while (~scanf("%lld", &L) && L)
{
++c;
ll d = gcd(8LL, L);
ll mod = 9LL * L / d;
ll phi = euler_phi(mod);
ll i, res = 0;
for (i = 1LL; i * i <= phi; ++i)
{
if (phi % i == 0 && mod_pow(10LL, i, mod) == 1LL)
{
res = i;
break;
}
}
for (; !res && i >= 1; --i)
{
if (phi % i == 0 && mod_pow(10LL, phi / i, mod) == 1LL)
{
res = phi / i;
break;
}
}
printf("Case %d: %lld\n", c, res);
}
return 0;
}