BZOJ-2242: [SDOI2011]计算器

[文章目录]

Description

你被要求设计一个计算器完成以下三项任务:
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)的最小非负整数。
1<=y,z,p<=10^9,为质数,1<=T<=10。

注意这不是亦或,是幂次。

1.快速幂啊,233

2.转化为xy+kp=z,显然extgcd,不过有个限定就是k<0。借鉴黄学长的方法,p=-p。然后再求。但是发现gcd为-,然后除完又变成正的。ans最后输出总为负。没办法,特判了一下。

3.早上看的题解,上午PoPoQQQ就讲了,哇,好开心(叫什么小步大步baby step giant step还有什么双向广搜meet in the middle,个人感觉就是分块)。

幂次肯定不超过p-1对吧【费马小定理】。考虑将幂次分解x=i*m+j。

=>y^(i*m+j)=z (%p)

=>y^j=zy^(p-1-im) (%p)        [ a^φ(p)≡1 (mod p&&gcd(a,p)==1) ]

所以,对于每一个i,我们求出来式子的右面,左面预处理出来,扔到哈希表里【然而这是个毛??算了,就当是map吧】,O(1)查询左面的是否存在,若存在一个j满足,那么i*m+j就是一个解。如果i从小开始枚举的话就是最小解了。然后嘛,m取√p的时候比较优秀。时间复杂度√p级别。好像还有什么特判什么的。

还有 一个重要的事情 :

%%%PoPoQQQ

#include <map>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
ll T,k,ans1,ans2,y,z,p;
map<ll,ll>v;
ll extgcd(ll a,ll b)
{
    if(b==0)
    {
        ans1=1;ans2=0;return a;
    }
    ll tmp=extgcd(b,a%b);
    ll t=ans1; ans1=ans2; ans2=t-a/b*ans2;
    return tmp;
}
ll pow(ll x,ll t)
{
    ll re=1;
    while(t)
    {
        if(t&1) re=re*x%p;
        x=x*x%p; t>>=1;
    }
    return re;
}
int main()
{
    scanf("%lld%lld",&T,&k);
    if(k==1)
    {
        while(T--)
        {
            scanf("%lld%lld%lld",&y,&z,&p);
            y%=p; printf("%lld\n",pow(y,z));
        }
    }
    if(k==2)
    {
        while(T--)
        {
            scanf("%lld%lld%lld",&y,&z,&p);
            p=-p; ll tmp=extgcd(y,p); p/=tmp;
            if(z%tmp) puts("Orz, I cannot find x!");
            else
            {
                z/=tmp; 
                ans1=ans1*z%p;
                if(p<0) p=-p;
                printf("%lld\n",(ans1%p+p)%p);
            }
        }
    }
    if(k==3)
    {
        while(T--)
        {
            scanf("%lld%lld%lld",&y,&z,&p); y%=p;

            ll m=sqrt(p),tmp=1; v.clear();
            if(!y&&!z){puts("1");continue;}
            if(!y){puts("Orz, I cannot find x!");continue;}
            for(ll i=0;i<m;i++)
            {
                if(v.find(tmp)==v.end()) v[tmp]=i;
                tmp=tmp*y%p;
            }
            bool flag=1;
            ll ine=pow(y,p-m-1); tmp=z;
            for(ll i=0;i<p;i+=m)
            {
                if(v.find(tmp)!=v.end())
                {
                    printf("%lld\n",i+v[tmp]);
                    flag=0;
                    break;
                }
                tmp=tmp*ine%p;
            }
            if(flag) puts("Orz, I cannot find x!");
        }
    }
    return 0;
}

 

发表评论

邮箱地址不会被公开。 必填项已用*标注