码迷,mamicode.com
首页 > 编程语言 > 详细

【EXT-BSGS算法求离散对数】POJ Clever Y 3243

时间:2015-08-28 23:23:46      阅读:197      评论:0      收藏:0      [点我收藏+]

标签:

Clever Y
Time Limit: 5000MS
Memory Limit: 65536K
Total Submissions: 7259
Accepted: 1795

Description

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

XY mod Z = K

Given X, Y, Z, we all know how to figure out K fast. However, given X,Z,K, 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 integersX,Z, K (0 ≤ X, Z, K ≤ 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 feasibleY (0 ≤Y < Z). Otherwise output the minimum Y you find.

Sample Input

5 58 33
2 4 3
0 0 0

Sample Output

9
No Solution

Source

POJ Monthly--2007.07.08, Guo, Huayang

 

题意:

X^Y%Z=K,计算等式成立的最小的Y值。

解题思路:

扩展BSGS算法,普通BSGS算法要求 A^x≡B( mod C )的C值为质数,因为等式有解的要求是GCD(A,C)|B,只有当C为质数,才一定成立。而此题并没有说C一定为质数。所以就要用到EXT-BSGS算法,看这个算法也是理解了好久。网上参考讲解这个算法的不多,找资料都找好久。自己总结下这个算法。

首先必须要会普通的BSGS,普通BSGS算法讲解:点击打开链接

      

        我们知道,普通的BSGS算法可以处理C为质数的情况,也就是保证GCD(A,C)|B,所以我们只要保证出现这种情况即可。怎么才能出现这种情况?我们可以让GCD(A,C)=1,这样就能保证它一定能被B整除。

      

        如何能让(A,C)=1?我们可以一直让C,除以(A,C)。当C把所有的A,C的公约数除尽之后,(A,C)一定等于1。注意,再求(A,C)时,C值是变换后的C值,即C[i]=C[i] / ( A,C[i-1] )。

       

        为了保证等式成立,我们必须用等式的每部分都除以这个值。我们一直循环C/(A,C),B/(A,C),而A^x的值不是A/(A,C)这点要注意。除的时候我们考虑的是从A^x次方中取出一个A除以(A,C),这时:A^x=A/(A,C)*A^(x-1)。

       

         我们的循环操作截止到(A,C)=1,所以在经过cnt次的操作后A^x=D*A^(x-cnt),因为我们总共取出cnt个A。我们每次循环还要更新D值,就是每次A/(A,C)的值乘以上次循环的值。即循环的是:D=D*A/(A,C)。所以我们这里D≠A^cnt。这点要注意一下。

      

        我们经过上述操作之后等式变成 D*A^(x′)≡B′ ( mod C′ ),x′=x-cnt。此时 只要我们求解出这个等式的解x′,就能求出x的值,x=x′+cnt。因为A*D≡B*D( mod C*D )等价于A≡B( mod C )。所以我们求得的解是等价的。

       

        而且在这里面我们(A,C)=1,这时我们就可以直接利用普通BSGS求解。

       

        等价为 A^(i*M)*D*A^j≡B( mod C )。我们查找合适的j值就可以了。

       

        最后我们还有一个重要的的问题没解决,我们看一个例子:49^x≡0( mod 343),很显然x=0,但是如果根据我们上述方法得出的结果就会是2。这里答案就显然变得不对,这里我们会发现答案如果本身小于cnt,再加上cnt的话就会变成一个不正确的值,所以我们可以尝试枚举一下所有小于cnt的x值,看下x值是否存在。如果存在的话直接返回x值即可,不用再进行BSGS步骤了。因为C每次最小消去的因子是2,所以cnt最大是log(C),我们枚举[0,log(C)]值就可以了。

  AC代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>

using namespace std;

const int MAXN = 1000010;
typedef long long LL;

bool hash[MAXN];
LL p[MAXN];
LL var[MAXN];

void insert_x(LL n,LL v)
{
    int x=v%MAXN;
    while(hash[x]&&var[x]!=v){
        x++;
        if(x==MAXN)
            x=0;
    }
    if(!hash[x]){
        p[x]=n;
        var[x]=v;
        hash[x]=true;
    }
}

LL find_x(LL v)
{
    int x=v%MAXN;
    while(hash[x]&&var[x]!=v){
        x++;
        if(x==MAXN)
            x=0;
    }
    if(hash[x]) return p[x];
    return -1;
}

LL gcd(LL a,LL b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}

LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0){
        x=1;y=0;
        return a;
    }
    LL r=exgcd(b,a%b,x,y);
    LL t=x;
    x=y;
    y=t-a/b*y;
    return r;
}

LL BSGS(LL A,LL B,LL C)
{
    LL n=1;
    for(int i=0;i<110;i++){//枚举所有小于log(C)的x值
        if(n==B%C) return i;
        n=n*A%C;
    }
    int cnt=0;
    LL res=1;
    LL divisor=gcd(A,C);
    while(divisor!=1){ //消去(A,C)的所有公约数
        if(B%divisor){
            return -1;
        }
        C/=divisor;
        B/=divisor;
        res=res*A/divisor%C;
        divisor=gcd(A,C);
        cnt++;
    }
    LL M=ceil(sqrt(C*1.0));
    LL temp=1;
    for(int i=0;i<M;i++){
        insert_x(i,temp);
        temp=temp*A%C;
    }
    for(int i=0;i<M;i++){
        LL x,y;
        LL r=exgcd(res,C,x,y);
        x=x*B;
        x=(x%C+C)%C;
        LL coordinate=find_x(x);
        if(coordinate!=-1){
            return (i*M+coordinate+cnt);
        }
        res=res*temp%C;
    }
    return -1;
}

int main()
{
    LL X,Z,K;
    while(scanf("%lld%lld%lld",&X,&Z,&K)!=EOF){
        if(!X&&!Z&&!K)break;
        memset(hash,false,sizeof(hash));
        memset(var,-1,sizeof(var));
        memset(p,-1,sizeof(p));
        LL coordinate=BSGS(X,K,Z);
        if(coordinate==-1) printf("No Solution\n");
        else printf("%lld\n",coordinate);
    }
    return 0;
}


版权声明:本文为博主原创文章,转载请注明出处。

【EXT-BSGS算法求离散对数】POJ Clever Y 3243

标签:

原文地址:http://blog.csdn.net/ydd97/article/details/48060553

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!