[LGOJ4884]多少个1?——[BSGS]

【题目描述】

给定整数K和质数m,求最小的正整数N,使得 11111⋯1(N个1) ≡K(modm)
说人话:就是 111…1111 mod m =K

【输入格式】

第一行两个整数,分别表示K和m

【输出格式】

一个整数,表示符合条件最小的N

S a m p l e    I n p u t Sample~~Input Sample  Input

9 17

S a m p l e    O u t p u t Sample~~Output Sample  Output

3

【题意分析】
111 ⋯ 1 ( x 个 1 ) = 1 0 x − 1 9 111\cdots1(x个1)=\frac{10^x-1}{9} 1111(x1)=910x1

所以
111 ⋯ 1 ( x 个 1 ) ≡ k ( m o d   p ) 111\cdots1(x个1)\equiv k(mod~p) 1111(x1)k(mod p)

就是求

1 0 x ≡ 9 k + 1 ( m o d   p ) 10^x\equiv9k+1(mod~p) 10x9k+1(mod p)

保证p是质数,裸的BSGS即可

但是sb出题人卡long long,再用__int128就行了

我用了神奇的乘法分配律 O ( 1 ) O(1) O(1)龟速乘,我也不知道是什么原理。。。

Code:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <map>
#include <algorithm>
using namespace std;

__int128 b, p;

inline __int128 read () {
    register __int128 s = 0, w = 1;
    register char ch = getchar ();
    while (! isdigit (ch)) {if (ch == '-') w = -1; ch = getchar ();}
    while (isdigit (ch)) {s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar ();}
    return s * w;
}

void write (__int128 x) {
    if (x < 0) putchar ('-'), x = -x;
    if (x > 9) write (x / 10);
    putchar (x % 10 + '0');
}

__int128 pow (__int128 a, __int128 b, __int128 qy) {
    if (! b) return 1; if (b == 1) return a;
    __int128 base = 1;
    while (b) {
        if (b & 1) base = base * a % qy;
        a = a * a % qy, b >>= 1;
    }
    return base;
}

__int128 mul (__int128 a, __int128 b, __int128 P){
    __int128 L = a * (b >> ((__int128)25)) % P * (((__int128)1) << 25) % P;
    __int128 R = a * (b & (((__int128)1) << 25) - 1) % P;
    return (L + R) % P;
}

__int128 BSGS (__int128 a, __int128 b, __int128 qy) {
    map <__int128, __int128> hash;
    __int128 lim = (__int128) ceil (sqrt ((double)qy)), base = b % qy;
    for (register __int128 i = 1; i <= lim; i++) hash[mul (b, pow (a, i, qy), qy)] = i;
    base = pow (a, lim, qy);
    __int128 o = 1;
    for (register __int128 i = 1; i <= lim; i++) {
        o = o * base % qy;
        if (hash[o]) return ((i * lim - hash[o]) % qy + qy) % qy;
    }
    return -1;
}

signed main () {
    b = read (), p = read ();
    b = (b * 9 + 1) % p;
    write (BSGS (10, b, p));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值