zoukankan      html  css  js  c++  java
  • bzoj2480 Spoj3105 Mod

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2480

    【题解】

    大步小步算法(BSGS)

    一直觉得BSGS不大优美因为算法里混杂着一个求逆元,这对推exgcd要好久的人不大兹磁啊。。

    参考:http://blog.miskcoo.com/2015/05/discrete-logarithm-problem

    顺带介绍一下BSGS算法。

    普通的BSGS:(p为质数)

    设m = ceil(sqrt(P))

    那么设A^(am+b)=B (mod P)

    那么有(A^m)^a = B * A^(-b) (mod P)

    那么把枚举右边所有取值(m种),用map存下,然后枚举a取值(m种),map查表即可。

    复杂度O(根号m*(logm))(看STL_map还是手写hash)

    扩展的BSGS:(A,P)>1

    我们转化模方程:A^x+kP=B(k为整数)

    那么令g=(A,P),有:A/g*A^(x-1)+kP/g=B/g

    如果B不能被g整除那么肯定无解。

    然后我们得到了新的方程A^(x-1) = B/g * (A/g)^(-1) (mod P/g)

    (注意右边不能约掉)

    然后我们按照这个步骤一直下去直到(a,p)=1,用普通BSGS解即可。注意加上化成BSGS需要的次数cnt。

    好了我们发现要一坨逆元,怎么办?

    考虑普通BSGS里的逆元:

    因为p不是质数了所以这个逆元很鬼畜啊要用exgcd求。

    不用急,我们让x=am-b即可。这样式子就变成了:
    那么有(A^m)^a = B * A^b (mod P)

    不过a的取值范围为[1,m+1],b为[0,m-1]而已。

    考虑extBSGS里的逆元:(A/g)

    我们把这一坨最后归到左边,就没有逆元了吧,然后查表的时候初值设成这个数即可。

    这样就很优美了吧

    比一直求逆元的bsgs跑的快多了

    # include <map>
    # include <math.h>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    inline int pwr(int a, int b, int P) {
        int ret = 1;
        while(b) {
            if(b&1) ret = 1ll * ret * a % P;
            a = 1ll * a * a % P;
            b >>= 1;
        }
        return ret;
    }
    
    map<int, int> mp;
    inline int BSGS(int A, int B, int P) {
    }
    
    inline int extBSGS(int A, int B, int P) {
        A %= P, B %= P;
        if(B == 1) return 0;
        int cnt = 0, d = 1;
        for (int g = __gcd(A, P); g!=1; g = __gcd(A, P)) {
            if(B % g) return -1;
            P /= g, B /= g;
            d = 1ll * d * A / g % P;
            ++cnt;
            if(B == d) return cnt;
        }
        
        mp.clear();
        int m = ceil(sqrt(1.0 * P)), t = B;
        for (int i=0; i<m; ++i) {
            mp[t] = i;
            t = 1ll * t * A % P;
        }
        int g = pwr(A, m, P); t = 1ll * d * g % P;
        for (int i=1; i<=m+1; ++i) {
            if(mp.count(t)) return cnt + i*m - mp[t];
            t = 1ll * t * g % P;
        }
        return -1;
    }
    
    int main() {
        int A, B, P, ans;
        while(cin >> A >> P >> B && (A+B+P)) {
            if(P == 1) {
                puts("0");
                continue;
            }
            ans = extBSGS(A, B, P);
            if(ans == -1) puts("No Solution");
            else printf("%d
    ", ans);
        }
        return 0;
    }
    
        
    View Code
  • 相关阅读:
    add() 方法用于向 <select> 添加一个 <option> 元素。
    jQuery LigerUI V1.2.3 (包括API和全部源码) 发布
    jQuery LigerUI V1.2.2 (包括API和全部源码) 发布
    SpringBoot整合Dubbo配合ZooKeeper注册中心
    【转】MySql 三大知识点——索引、锁、事务
    Redis持久化背后的故事
    利用Docker搭建Redis集群
    synchronized的实现原理与应用
    ConcurrentHashMap
    volatile的内存语义与应用
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj2480.html
Copyright © 2011-2022 走看看