BZOJ2242 [SDOI2011]计算器 题解&代码

题意:有三种要求:
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显然是快速幂了,纯模板
2是扩展欧几里得(exgcd),求满足xy-pk=z的最小x(k任意)
3利用了费马小定理的性质a^(p-1)≡1(mod p),然后分块降复杂度(太麻烦懒得写直接抄黄学长代码…捂脸)

/************************************************************** Problem: 2242 User: Rainbow6174 Language: C++ Result: Accepted Time:2028 ms Memory:3272 kb ****************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#define LL long long
using namespace std;
int T,k;
map<int,int> vis;
LL y,z,x,a,b,m,t,mod,temp,flag;
LL pow(LL base,LL x)
{
    LL ret = 1;
    base %= mod;
    while(x)
    {
        if(x & 1)ret *= base,ret %= mod;
        base *= base;
        base %= mod;
        x >>= 1;
    }
    return ret;
}
LL gcd(LL x,LL y)
{
    if(!y)return x;
    return gcd(y,x%y);
}
LL exgcd(LL x,LL y)
{
    if(!y)
    {
        a=1,b=0;
        return x;
    }
    int ret=exgcd(y,x%y);
    //cout<<a<<' '<<b<<' '<<x<<' '<<y<<endl;
    temp=a;
    a=b;
    b=temp-(x/y)*b;
    return ret;
}
int main(void)
{
    //freopen("calc.in","r",stdin);
    //freopen("calc.out","w",stdout);
    scanf("%d%d",&T,&k);
    while(T--)
    {
        scanf("%lld%lld%lld",&y,&z,&mod);
        if(k==1)printf("%lld\n",pow(y,z));
        y%=mod;
        z%=mod;
        if(k==2)
        {
            if(!z)
            {
                printf("0\n");
                continue;
            }
            if(!y || gcd(y,mod)>z)
            {
                printf("Orz, I cannot find x!\n");
                continue;
            }
            //cout<<y<<' '<<mod<<endl;
            exgcd(y,mod);
            a+=mod;
            a%=mod;
            a*=z/gcd(y,mod);
            a%=mod;
            printf("%lld\n",a);
        }
        if(k==3)
        {
            flag=0;
            if(!y)
            {
                if(!z)puts("1");
                else puts("Orz, I cannot find x!");
                continue;
            }
            vis.clear();
            LL a=ceil(sqrt(mod)),t=1;
            vis[1]=a+1;
            for(LL i=1;i<a;i++)
            {
                t=t*y%mod;
                if(!vis[t])vis[t]=i;
            }
            temp=pow(y,mod-a-1),b=1;
            for(LL i=0;i<a;i++)
            {
                int temp1=vis[z*b%mod];
                if(temp1)
                {
                    if(temp1==a+1)temp1=0;
                    printf("%lld\n",i*a+temp1);
                    flag=1;
                    break;
                }
                b=b*temp%mod;
            }
            if(!flag)puts("Orz, I cannot find x!");
        }
    }
}

你可能感兴趣的:(BZOJ2242 [SDOI2011]计算器 题解&代码)