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

来源:互联网 发布:mac os 五笔输入法 编辑:程序博客网 时间:2024/05/18 02:20

题目描述

传送门
题目描述有问题!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 longint 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;            }        }    }}
0 0
原创粉丝点击