[数论][构造][离散对数] Codeforces 913 G. Power Substring

Solution

a 长度为n
可以尝试构造一个数 b ,使得a10m+b成为其后缀。
就等价于 x=a10m+b2k(mod10n+m)
构造 kn+m ,那要满足这样的 k 就等价于2n+mx5x
假如说现在有 xa10m ,要怎么构造满足上述两个条件的数 x 呢?
2n+mx,则 x=2n+mxmod2n+m
5x ,则 x=x+2n+m
如何解出 k
2kx(mod10n+m),有 2n+m2k,2n+mx,2n+m10n+m
所以 2knmx2n+m(mod5n+m) 。设 y=x2n+m
k=n+m+log2y
这里有一个结论 2 5α的原根。
一个更广泛的结论: g 是奇质数p的原根,有 g pα的原根。
证明:

  • d φ(p)的质因子,有 gpα1(p1)d=(gp1d)pα1gp1d≢1(modpα)
  • 只需要证 gpα2≢1(modpα) ,发现 xp1(modpa) xp1(modpb)ba 的充分条件。所以就等价于 g≢1(modp2)

但这个模数很大,BSGS是跑不过去的。
dy,i 为模 pi 意义下的 loggy ,有 di+1=di+jφ(pi),j[0,p) ,枚举就好了。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

int test, n;
ll a, b, t, l, x, y, MOD, tp, p5;

inline int diglen(ll x) {
    static int cnt;
    for (cnt = 0; x; cnt++) x /= 10;
    return cnt;
}
inline ll Mul(ll a, ll b, ll MOD) {
    ll c = 0;
    while (b > 0) {
        if (b & 1) c = (c + a) % MOD;
        a = (a + a) % MOD; b >>= 1;
    }
    return c;
}
inline ll Pow(ll a, ll b, ll MOD) {
    ll c = 1;
    while (b > 0) {
        if (b & 1) c = Mul(c, a, MOD);
        a = Mul(a, a, MOD); b >>= 1;
    }
    return c;
}

int main(void) {
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
    cin >> test;
    while (test--) {
        cin >> a; n = diglen(a);
        tp = 1;
        for (int m = 0; ; m++) {
            x = a; MOD = 1ll << (n + m);
            if (x % MOD != 0) x += MOD - x % MOD;
            if (x % 5 == 0) x += MOD;
            if (x % MOD == 0 && x % 5 != 0 && x - a < tp) {
                y = x >> (n + m);
                t = 0;
                if (y % 5 == 0) t = -1;
                if (y % 5 == 1) t = 0;
                if (y % 5 == 2) t = 1;
                if (y % 5 == 3) t = 3;
                if (y % 5 == 4) t = 2;
                p5 = 5;
                for (int i = 1; i < n + m; i++){
                    while (Pow(2, t, p5 * 5) != y % (p5 * 5))
                        t += p5 / 5 * 4;
                    p5 *= 5;
                }
                cout << t + n + m << endl;
                break;
            }
            a *= 10; tp *= 10;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值