[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
#include
#include
#include
#include
#include
using namespace std;
#define LL long long

int T,type;
LL y,z,p,ans;
map  hash;

LL fast_pow(LL a,LL p,LL Mod)
{
    LL ans=1;
    for (;p;p>>=1LL,a=a*a%Mod)
        if (p&1LL)
            ans=ans*a%Mod;
    return ans;
}
LL gcd(LL a,LL b)
{
    if (!b) return a;
    else return gcd(b,a%b);
}
void exgcd(LL a,LL b,LL &x,LL &y)
{
    if (!b) x=1,y=0;
    else exgcd(b,a%b,y,x),y-=a/b*x;
}
LL EXgcd(LL a,LL b,LL c)
{
    LL t=gcd(a,b);
    if (c%t) return -1;
    a/=t,b/=t,c/=t;
    LL x=0,y=0;
    exgcd(a,b,x,y);
    x=(x%b+b)%b;
    if (!x) x+=b;
    return (x*c%b+b)%b;
}
LL bsgs(LL a,LL b,LL p)
{
    if (a%p==0) return -1;
    hash.clear();
    LL m=ceil(sqrt(p));
    LL a_m=fast_pow(a,m,p);
    LL mul=b;
    for (LL j=0;j<=m;++j)
    {
        hash[mul]=j+1;
        mul=mul*a%p;
    }
    mul=1;
    for (LL i=1;i<=m;++i)
    {
        mul=mul*a_m%p;
        if (hash[mul]) return i*m-(hash[mul]-1);
    }
    return -1;
}
int main()
{
    scanf("%d%d",&T,&type);
    while (T--)
    {
        scanf("%lld%lld%lld",&y,&z,&p);
        switch(type)
        {
            case 1:
                {
                    ans=fast_pow(y,z,p);
                    printf("%lld\n",ans);
                    break;
                }
            case 2:
                {
                    ans=EXgcd(y,p,z);
                    if (ans==-1) puts("Orz, I cannot find x!");
                    else printf("%lld\n",ans);
                    break;
                }
            case 3:
                {
                    ans=bsgs(y,z,p);
                    if (ans==-1) puts("Orz, I cannot find x!");
                    else printf("%lld\n",ans);
                    break;
                }
        }
    }
}

你可能感兴趣的:(题解,省选,扩欧,BSGS)