【BZOJ2242】【SDOI2011】计算器(快速幂+扩欧+BSGS)

题目描述

传送门
题目描述有问题! y,z,p 中只有 p 为质数!
题目描述有问题! y,z,p 中只有 p 为质数!
题目描述有问题! y,z,p 中只有 p 为质数!
重要的事情说三遍!

题解

对于操作1:
快速幂而已,不存在无解的情况。
对于操作2:
扩展欧几里得算法。有解的条件为: gcd(y,p)|z
证明:
已知

xyz(modp)

原式可化为:
xyap=z

问题可以转化为求是否有一组数x,a使 xyap=z
而如果把所有x,a的取值以及对应的 xyap 的得数建系的话,会发现最小的数为x,a的gcd,而其他所有的数都为gcd的倍数。
这样我们就可以得出:有解的条件为: gcd(y,p)|z

我们知道当 (y,p)=1 时我们可以利用扩展欧几里得求出 xyap=gcd(y,p) xyap=1 的解 x,a
所以将原式转换一下:

xzy+azp=1

xz=xaz=a ,求出x’和a’的值再与z相乘即为答案。

有人有问题吗?

能用扩展欧几里得求这个式子 xzy+azp=1 的解条件不是y,p互质吗?那要不要判断一下呢?
其实是不用的,因为如果满足这个式子 gcd(y,p)|z 的话,我们可以让等式两边同时/gcd(y,p),也就是y,z,p同时/gcd(y,p)。这样的话就保证了y,p一定互质啦。
对于操作3:
只是BSGS算法的模板啦,可以参考本博客BSGS算法学习笔记。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define LL long long

int T,K,Y,Z,P;
LL ans,m,Y_m,mul,now,x,y,d;
map <LL,LL> hash;
bool pd;

inline LL fast_pow(LL a,LL p){
    LL ans=1;
    for (;p;p>>=1,a=a*a%P)
      if (p&1)
        ans=ans*a%P;
    return ans;
}

inline LL gcd(LL a,LL b){
    if (!b) return a;
    else return gcd(b,a%b);
}

inline void exgcd(LL a,LL b,LL &x,LL &y,LL &d){
    if (!b) x=1,y=0,d=a;
    else exgcd(b,a%b,y,x,d),y-=a/b*x;
}

int main(){
    scanf("%d%d",&T,&K);
    while (T--){
        scanf("%d%d%d",&Y,&Z,&P);
        switch (K){
            case 1:{
                ans=fast_pow(Y,Z);
                printf("%lld\n",ans);
                break;
            }
            case 2:{
                LL GCD=gcd(Y,P);
                if (Z%GCD){
                    printf("Orz, I cannot find x!\n");
                    continue;
                }
                Y/=GCD; Z/=GCD; P/=GCD;
                exgcd(Y,P,x,y,d);
                x=(x%P+P)%P;
                x=x*Z%P;
                printf("%lld\n",x);
                break;
            }
            case 3:{
                if (Y%P==0){
                    printf("Orz, I cannot find x!\n");
                    continue;
                }
                hash.clear();
                pd=false;

                m=ceil(sqrt(P));
                Y_m=fast_pow(Y,m);

                mul=1;
                now=mul*Z;
                hash[now]=0;
                for (int j=1;j<=m;++j){
                    mul=mul*Y%P;
                    now=mul*Z%P;
                    hash[now]=j;
                }

                mul=1;
                for (int i=1;i<=m;++i){
                    mul=mul*Y_m%P;
                    if (hash[mul]){
                        pd=true;
                        ans=i*m-hash[mul];
                        printf("%lld\n",ans);
                        break;
                    }
                }

                if (!pd) printf("Orz, I cannot find x!\n");

                break;
            }
        }
    }
}

你可能感兴趣的:(快速幂,bzoj,BSGS,SDOI,扩欧)