bzoj 3239: Discrete Logging BSGS

4 篇文章 0 订阅

Description

Given a prime P, 2 <= P < 231, an integer B, 2 <= B < P, and an integer N, 2 <= N < P, compute the discrete logarithm of N, base B, modulo P. That is, find an integer L such that

BL == N (mod P)

Input

Read several lines of input, each containing P,B,N separated by a space,

Output

for each line print the logarithm on a separate line. If there are several, print the smallest; if there is none, print “no solution”.

The solution to this problem requires a well known result in number theory that is probably expected of you for Putnam but not ACM competitions. It is Fermat’s theorem that states

B(P-1) == 1 (mod P)
for any prime P and some other (fairly rare) numbers known as base-B pseudoprimes. A rarer subset of the base-B pseudoprimes, known as Carmichael numbers, are pseudoprimes for every base between 2 and P-1. A corollary to Fermat’s theorem is that for any m

B(-m) == B(P-1-m) (mod P) .
Sample Input

5 2 1

5 2 2

5 2 3

5 2 4

5 3 1

5 3 2

5 3 3

5 3 4

5 4 1

5 4 2

5 4 3

5 4 4

12345701 2 1111111

1111111121 65537 1111111111

Sample Output

0

1

3

2

0

3

1

2

0

no solution

no solution

1

9584351

462803587

分析:显然是一道BSGS模版题。

代码:

/**************************************************************
    Problem: 3239
    User: beginend
    Language: C++
    Result: Accepted
    Time:172 ms
    Memory:118488 kb
****************************************************************/

#include <iostream>
#include <cstdio>
#include <cmath>

const int maxn=5000001;

using namespace std;

long long b,a,p,block,i,t,power;
long long g[maxn],cnt;

struct node
{
    long long x,pow;
}hash[maxn];//一个hash表

long long f(long long x)//hash函数
{
    return x%maxn;
}

void updata(long long x,long long c)//插入
{
    long long id=f(x);
    while (hash[id].x!=0) id=(id+1)%maxn;
    hash[id].x=x;
    hash[id].pow=c;
    g[++cnt]=id;
}

long long find(long long x)//查询
{
    long long id=f(x);
    while (hash[id].x!=0)
    {
        if (hash[id].x==x) return hash[id].pow; 
        id=(id+1)%maxn;
    }
    return -1;
}

int main()
{   
    while (scanf("%lld%lld%lld",&p,&a,&b)!=EOF)
    {
        if (b==1) //特判一下1
        {
            printf("0\n");
            continue;
        }       
        block=trunc(sqrt(p))+1;//分块,先处理a^0到a^(block-1)
        a%=p; b%=p; cnt=0;
        power=1;
        for (i=0;i<block;i++)
        {
            updata((power*b)%p,i);//把a^0到a^(block-1)压人hash表
            power=(power*a)%p;
        }
        t=1;
        for (i=1;i<=block;i++)
        {
            t=(t*power)%p;//一个(a^block)^i,
            long long j=find(t);//寻找是否有解
            if (j!=-1)
            {
                printf("%lld\n",i*block-j);//当前幂次为i*block-j
                break;
            }
        }
        if (i>block) printf("no solution\n");
        for (i=1;i<=cnt;i++) hash[g[i]].x=0;//清空hash表
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值