POJ 3243 Clever Y BSGS 算法 (模板)

Clever Y
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 8920 Accepted: 2222
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 integers X, 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 feasible Y (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

BSGS 算法主要解决的是A^x=B (mod C)这类高次同余方程 的问题

证明的话 大概就是把x替换一下 令x=i*k-j的形式 然后预处理一部分放到hash表中 然后在枚举另外一部分,看能不能在hash表中找到。

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define lint __int64
#define MAXN 131071
struct HashNode { lint data, id, next; };
HashNode hash[MAXN<<1];
bool flag[MAXN<<1];
lint top;

void Insert ( lint a, lint b )
{
    lint k = b & MAXN;
    if ( flag[k] == false )
    {
        flag[k] = true;
        hash[k].next = -1;
        hash[k].id = a;
        hash[k].data = b;
        return;
    }
    while( hash[k].next != -1 )
    {
        if( hash[k].data == b ) return;
        k = hash[k].next;
    }
    if ( hash[k].data == b ) return;
    hash[k].next = ++top;
    hash[top].next = -1;
    hash[top].id = a;
    hash[top].data = b;
}

lint Find ( lint b )
{
    lint k = b & MAXN;
    if( flag[k] == false ) return -1;
    while ( k != -1 )
    {
        if( hash[k].data == b ) return hash[k].id;
        k = hash[k].next;
    }
    return -1;
}

lint gcd ( lint a, lint b )
{
    return b ? gcd ( b, a % b ) : a;
}

lint ext_gcd (lint a, lint b, lint& x, lint& y )
{
    lint t, ret;
    if ( b == 0 )
    {
        x = 1, y = 0;
        return a;
    }
    ret = ext_gcd ( b, a % b, x, y );
    t = x, x = y, y = t - a / b * y;
    return ret;
}

lint mod_exp ( lint a, lint b, lint n )
{
    lint ret = 1;
    a = a % n;
    while ( b >= 1 )
    {
        if( b & 1 )
            ret = ret * a % n;
        a = a * a % n;
        b >>= 1;
    }
    return ret;
}

lint BabyStep_GiantStep ( lint A, lint B, lint C )
{
    top = MAXN;  B %= C;
    lint tmp = 1, i;
    for ( i = 0; i <= 100; tmp = tmp * A % C, i++ )
        if ( tmp == B % C ) return i;

    lint D = 1, cnt = 0;
    while( (tmp = gcd(A,C)) !=1 )
    {
        if( B % tmp ) return -1;
        C /= tmp;
        B /= tmp;
        D = D * A / tmp % C;
        cnt++;
    }

    lint M = (lint)ceil(sqrt(C+0.0));
    for ( tmp = 1, i = 0; i <= M; tmp = tmp * A % C, i++ )
        Insert ( i, tmp );

    lint x, y, K = mod_exp( A, M, C );
    for ( i = 0; i <= M; i++ )
    {
        ext_gcd ( D, C, x, y ); // D * X = 1 ( mod C )
        tmp = ((B * x) % C + C) % C;
        if( (y = Find(tmp)) != -1 )
            return i * M + y + cnt;
        D = D * K % C;
    }
    return -1;
}

int main()
{
    lint A, B, C;
    while( scanf("%I64d%I64d%I64d",&A,&C,&B ) !=EOF )
    {
        if ( !A && !B && !C ) break;
        memset(flag,0,sizeof(flag));
        lint tmp = BabyStep_GiantStep ( A, B, C );
        if ( tmp == -1 )puts("No Solution");
        else printf("%I64d\n",tmp);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值