BZOJ_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS

BZOJ_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS

题意:

你被要求设计一个计算器完成以下三项任务:
1、给定y,z,p,计算Y^Z Mod P 的值;
2、给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数;
3、给定y,z,p,计算满足Y^x ≡ Z ( mod P)的最小非负整数。
 
分析:
各种板子题
 
代码:
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <math.h>
using namespace std;
#define LL long long
map<LL,int> mp; 
LL qp(LL x,LL y,LL mod){
    LL re=1;
    while(y){
        if(y&1ll)re=re*x%mod;
        x=x*x%mod;
        y>>=1ll;
    }
    return re;
}
void exgcd(LL a,LL b,LL &x,LL &y,LL &p){
    if(!b){x=1;y=0;p=a;return ;}
    exgcd(b,a%b,y,x,p);
    y-=(a/b)*x;
}
LL BSGS(LL n,LL a,LL b){
    if(n==1)if(!b)return a!=1; else return -1;
    if(b==1)if(a)return 0; else return -1;
    if(a%n==0)if(!b)return 1; else return -1;
    LL m=ceil(sqrt(n)),d=1,base=1;
    mp.clear();
    for(int i=0;i<m;i++)
    {
        if(!mp.count(base))mp[base]=i;
        base=(base*a)%n;
    }
    for(int i=0;i<m;i++)
    {
        LL x,y,s;
        exgcd(d,n,x,y,s);
        x=(x*b%n+n)%n;
        if(mp.count(x))return i*m+mp[x];
        d=(d*base)%n;
    }
    return -1;
}
int main()
{
    int t,k;
    scanf("%d%d",&t,&k);
    int i;
    LL a,b,n,x,y,p;
    for(i=1;i<=t;i++){
        scanf("%lld%lld%lld",&a,&b,&n);
        if(k==1){
            printf("%lld\n",qp(a,b,n));
        }else if(k==2){
            exgcd(a,n,x,y,p);
            if(b%p){
                puts("Orz, I cannot find x!");continue; 
            }
            x=(x*(b/p)%n+n)%n;
            printf("%lld\n",x);
        }else if(k==3){
            LL x=BSGS(n,a,b);
            if(x==-1)puts("Orz, I cannot find x!");
            else printf("%lld\n",x);
        }
    }
}

 

posted @ 2018-03-17 22:22  fcwww  阅读(224)  评论(0编辑  收藏  举报