洛谷 P4454 [CQOI2018]破解D-H协议

题面

题意

给出四个数g,p,A,B,其中有a,b满足g^a%p=A,g^b%p=B.求g^(a*b)%p.

做法

首先a,b< p,可以发现只要求出a,b中的任意一个值即可得到答案,但如果暴力枚举a的话复杂度为O(p),显然过不了.
可以考虑分块,令k=sqrt(p),那么就可以得到如下等式:
a=u*p+v(u,v<=k)
所以g^(u *p) *g^v=A
移项得g^(u *p)=A *Inv(g^v)
因此可以预处理出Inv(g^v)(0<= v < k)的值,存到一个map中,然后暴力枚举u就可以求出a,其复杂度为O(sqrt(n)*log(n)).

代码

#include<iostream>
#include<cstdio>
#include<map>
#define ll long long
using namespace std;

ll g,M,A,B,T,sq;
map<ll,ll>mm;

inline ll po(ll u,ll v)
{
    ll res=1;
    for(;v;)
    {
        if(v&1) res=res*u%M;
        u=u*u%M;
        v>>=1;
    }
    return res;
}

inline void get()
{
    ll i;
    for(i=0;i*i<=M;i++)
    {
        mm[po(g,i)]=i;
    }
    sq=i-1;
}

int main()
{
    ll i,j,tmp;
    cin>>g>>M>>T;
    get();
    while(T--)
    {
        scanf("%lld%lld",&A,&B);
        for(i=0;;i++)
        {
            tmp=A*po(po(g,i*sq),M-2)%M;
            if(mm.count(tmp))
            {
                printf("%lld\n",po(B,i*sq+mm[tmp]));
                break;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/yzyyylx/article/details/79979089