洛谷传送门
题目描述
给定整数 K K K和质数 m m m,求最小的正整数 N N N,使得 1 ⋯ 1 1\cdots1 1⋯1( N N N个 1 1 1) ≡ K ( m o d m ) \equiv K \pmod m ≡K(modm)
说人话:就是 111...1111 m o d m = K 111...1111\ mod\ m =K 111...1111 mod m=K
输入输出格式
输入格式:
第一行两个整数,分别表示 K K K和 m m m
输出格式:
一个整数,表示符合条件最小的 N N N
输入输出样例
输入样例#1:
9 17
输出样例#1:
3
说明
30%的数据保证 m ≤ 1 0 6 m\leq 10^6 m≤106
60%的数据保证 m ≤ 5 ∗ 1 0 7 m\leq 5*10^7 m≤5∗107
100%的数据保证 2 ≤ m ≤ 1 0 11 , 0 ≤ K < m 2\leq m\leq 10^{11},0\leq K< m 2≤m≤1011,0≤K<m
解题分析
11 ⋯ 11 11\cdots 11 11⋯11不好表示, 我们就把它 × 9 \times 9 ×9再 + 1 +1 +1, 然后就变成了 1 0 n ≡ K × 9 + 1 ( m o d m ) 10^n\equiv K\times 9+1 (mod\ m) 10n≡K×9+1(mod m)。
显然就可以用 B S G S BSGS BSGS搞了, 注意需要龟速乘。
总复杂度 O ( N l o g ( N ) ) O(\sqrt Nlog(\sqrt N)) O(Nlog(N))。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <map>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
std::map <ll, int> mp;
IN ll fmul(ll a, ll b, ll mod)
{
ll ret = 0;
W (b)
{
if(b & 1) ret = (ret + a) % mod;
a = (a << 1) % mod, b >>= 1;
}
return ret;
}
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if(!b) return x = 1, y = 0, a;
ll ret = exgcd(b, a % b, x, y);
ll buf = x; x = y, y = buf - a / b * y;
}
IN ll BSGS(ll A, ll B, ll mod)
{
if(mod == 1) if(!B) return 0; else return -1;
if(B == 1) if(A) return 0; else return -1;
if(!(A % mod)) if(B % mod) return -1; else return 1;
ll bd = std::ceil(std::sqrt(mod));
ll now = 1, base = 1;
for (R int i = 0; i < bd; ++i)
{
if(!mp.count(base)) mp[base] = i;
base = fmul(base, A, mod);
}
ll x, y, gcd;
for (R int i = 0; i < bd; ++i)
{
gcd = exgcd(now, mod, x, y);
x = (x % mod + mod) % mod;
x = fmul(x, B, mod);
if(mp.count(x)) return mp[x] + 1ll * i * bd;
now = fmul(now, base, mod);
}
return -1;
}
int main(void)
{
ll b, mod;
in(b), in(mod);
b = (b * 9 + 1) % mod;
printf("%lld", BSGS(10, b, mod));
}