zoukankan      html  css  js  c++  java
  • POJ 3243 Clever Y(离散对数-拓展小步大步算法)

    Description

    Little Y finds there is a very interesting formula in mathematics:

    XY mod Z = K

    Given XYZ, we all know how to figure out K fast. However, given XZK, could you figure out Y fast?

    Input

    Input data consists of no more than 20 test cases. For each test case, there would be only one line containing 3 integers XZK (0 ≤ XZK ≤ 109). 
    Input file ends with 3 zeros separated by spaces. 

    Output

    For each test case output one line. Write "No Solution" (without quotes) if you cannot find a feasible Y (0 ≤ Y < Z). Otherwise output the minimum Y you find.
     
    题目大意:求离散对数。没有保证Z一定是素数。
    PS:说一下上面没有提到的一个东西,最后一个O(sqrt(m))的循环中,逆元是没有必要每次都求的,可以预先求出来,让算法复杂度降至O(sqrt(m))。
    在我的代码中,v = k^(-1) * a^(-i*m),可以在前面先求出k^(-1)和a^(-m),然后每次v都乘以a^(-m),而不需要每次对k*a^(i*m)求逆元。
     
    代码(63MS):
     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cmath>
     6 using namespace std;
     7 typedef long long LL;
     8 
     9 const int SIZEH = 65537;
    10 
    11 struct hash_map {
    12     int head[SIZEH], size;
    13     int next[SIZEH];
    14     LL state[SIZEH], val[SIZEH];
    15 
    16     void init() {
    17         memset(head, -1, sizeof(head));
    18         size = 0;
    19     }
    20 
    21     void insert(LL st, LL sv) {
    22         LL h = st % SIZEH;
    23         for(int p = head[h]; ~p; p = next[p])
    24             if(state[p] == st) return ;
    25         state[size] = st; val[size] = sv;
    26         next[size] = head[h]; head[h] = size++;
    27     }
    28 
    29     LL find(LL st) {
    30         LL h = st % SIZEH;
    31         for(int p = head[h]; ~p; p = next[p])
    32             if(state[p] == st) return val[p];
    33         return -1;
    34     }
    35 } hashmap;
    36 
    37 void exgcd(LL a, LL b, LL &x, LL &y) {
    38     if(!b) x = 1, y = 0;
    39     else {
    40         exgcd(b, a % b, y, x);
    41         y -= x * (a / b);
    42     }
    43 }
    44 
    45 LL inv(LL a, LL n) {
    46     LL x, y;
    47     exgcd(a, n, x, y);
    48     return (x + n) % n;
    49 }
    50 
    51 LL pow_mod(LL x, LL p, LL n) {
    52     LL ret = 1;
    53     while(p) {
    54         if(p & 1) ret = (ret * x) % n;
    55         x = (x * x) % n;
    56         p >>= 1;
    57     }
    58     return ret;
    59 }
    60 
    61 LL BabyStep_GiantStep(LL a, LL b, LL n) {
    62     for(LL i = 0, e = 1; i <= 64; ++i) {
    63         if(e == b) return i;
    64         e = (e * a) % n;
    65     }
    66     LL k = 1, cnt = 0;
    67     while(true) {
    68         LL t = __gcd(a, n);
    69         if(t == 1) break;
    70         if(b % t != 0) return -1;
    71         n /= t; b /= t; k = (k * a / t) % n;
    72         ++cnt;
    73     }
    74     hashmap.init();
    75     hashmap.insert(1, 0);
    76     LL e = 1, m = LL(ceil(sqrt(n + 0.5)));
    77     for(int i = 1; i < m; ++i) {
    78         e = (e * a) % n;
    79         hashmap.insert(e, i);
    80     }
    81     LL p = inv(pow_mod(a, m, n), n), v = inv(k, n);
    82     for(int i = 0; i < m; ++i) {
    83         LL t = hashmap.find((b * v) % n);
    84         if(t != -1) return i * m + t + cnt;
    85         v = (v * p) % n;
    86     }
    87     return -1;
    88 }
    89 
    90 int main() {
    91     LL x, z, k;
    92     while(cin>>x>>z>>k) {
    93         if(x == 0 && z == 0 && k == 0) break;
    94         LL ans = BabyStep_GiantStep(x % z, k % z, z);
    95         if(ans == -1) puts("No Solution");
    96         else cout<<ans<<endl;
    97     }
    98 }
    View Code
  • 相关阅读:
    Ubuntu16.04+GTX2070+Driver418.43+CUDA10.1+cuDNN7.6
    N皇后问题
    Linux Bash之通配符
    Linux Bash之正则表达式
    Linux Bash文本操作之grep篇
    Linux Bash文本操作之sed篇其二
    Integer对象两种创建方式的比较
    Class文件版本号
    group by、group_concat()、if()
    字节码命令与Java语言在语义描述能力上的差异
  • 原文地址:https://www.cnblogs.com/oyking/p/3633263.html
Copyright © 2011-2022 走看看