POJ 3696 同余 + 欧拉函数

题意

传送门 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 88=8×11=8×(10x1)/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(10x1) 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)×(10x1)/9,则有 ( L / d )   ∣   ( 1 0 x − 1 ) / 9 (L/d)\ | \ (10^x-1)/9 (L/d)  (10x1)/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(L logL)。考虑到模数较大,直接做乘法会有 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值