bzoj2242: [SDOI2011]计算器 && BSGS 算法

BSGS算法

给定y、z、p,计算满足yx mod p=z的最小非负整数x。p为质数(没法写数学公式,以下内容用心去感受吧)

x = i*m + j.

y^(j)≡z∗y^(-i*m)) (mod p)

y^(j)≡z∗ine(y^(i*m)) (mod p)(逆元)

由费马小定理y^(p-1)≡1 (mod p) ine(y^m) = y^(p-m-1) 

ine(y^(i*m)≡ine(y^((i−1)m))∗y^(p-m-1) 

1.首先枚举同余符号左面,用一个hash保存(y^j,j),因为j可能等于0,所以hash[1]要赋为一个特殊值。

2.再枚举同余符号右面,如果hash(z∗ine(y^(i*m)))存在,就找到了一组解。

显然,m=sqrt(p)的时候复杂度最低为O(sqrt(p)),m=ceil(sqrt(p)).

 

从这个人博客中可以看出,这个人对于BSGS算法有着相当深刻的理解,居然能够找到俩个有助于学习BSGS算法的俩首歌,还用了exgcd算法。

http://www.cnblogs.com/yuiffy/p/3877381.html

 

其他俩个操作为快速幂,exgcd。

因为题目并不是一起写的,所以写了俩个快速幂。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
using namespace std;

int T,k;
long long y,z,p;
map<int,int> hash;

long long q(long long z) {
    if(z==1) return y%p;
    long long m=q(z/2);
    if(z%2) return (((m*m)%p)*y)%p;
    return (m*m)%p;
}

void solve1() {
    printf("%lld\n",q(z));    
}

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

void solve2(long long a,long long b,long long n) {
    long long x,y,ans,d,s;
    d=exgcd(a,n,x,y);
    if(b%d!=0) printf("Orz, I cannot find x!\n");
    else {
        ans=(b/d)*x; s=n/d;
        ans=(ans%s+s)%s;
        printf("%lld\n",ans);
    }
}

long long power(long long a,long long b,long long mod) {
    long long res=1;
    while(b) {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}

void solve3() {
    y%=p; z%=p;
    if(!y && !z) printf("1\n");
    else if(!y) printf("Orz, I cannot find x!\n"); 
    else {
        long long m,v,e,res;
        m=ceil(sqrt(p)); v=power(y,p-m-1,p); e=1;    
        
        hash.clear();
        hash[1]=m+1;
        for(long long i=1;i<=m;i++) {
            e=e*y%p;
            if(!hash[e]) hash[e]=i;    
        }
        
        res=-1;
        for(long long i=0;i<m;i++) {
            if(hash[z]) {
                res=i*m+(hash[z]==m+1?0:hash[z]);
                break;            
            }
            z=z*v%p;            
        }
        if(res==-1) printf("Orz, I cannot find x!\n");
        else printf("%d\n",res);
    }
}

int main() {
    scanf("%d%d",&T,&k);
    while(T--) {
        scanf("%lld%lld%lld",&y,&z,&p);
        if(k==1) solve1();
        else if(k==2) solve2(y,z,p);
        else solve3();
    }
    return 0;
}
posted @ 2016-06-15 20:50  invoid  阅读(761)  评论(1编辑  收藏  举报