BZOJ 2242

2242: [SDOI2011]计算器

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 5142  Solved: 1964
[Submit][Status][Discuss]

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)的最小非负整数。

Input

 输入包含多组数据。

第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。
以下行每行包含三个正整数y,z,p,描述一个询问。

Output

对于每个询问,输出一行答案。对于询问类型2和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”,注意逗号与“I”之间有一个空格。

Sample Input

【样例输入1】
3 1
2 1 3
2 2 3
2 3 3
【样例输入2】
3 2
2 1 3
2 2 3
2 3 3
【数据规模和约定】
对于100%的数据,1<=y,z,p<=10^9,为质数,1<=T<=10。

Sample Output

【样例输出1】
2
1
2
【样例输出2】
2
1
0

HINT

 

Source

 
此题做法多种多样(我指的是第二问hhh)
1:quickpow ; 3:bsgs 无疑问
2:可以用exgcd,也可以直接用一下逆元,毕竟p是素数。
为了复习exgcd,我决定用比较烦的exgcd做
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<complex>
#include<map>
#include<cstring>
#define ll long long
using namespace std;
ll read()
{
    ll x=0,f=1;char s=getchar();
    while(s<'0' || s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0' && s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
ll y,z,p;
ll pow(ll a,ll x)
{
    ll ans=1;
    for(;x>0;x>>=1,a=a*a%p)
        if(x&1)ans=ans*a%p;
    return ans%p;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0){x=1;y=0;return a;}
    ll q=exgcd(b,a%b,y,x);y-=(a/b)*x;
    return q;
}
ll T,K;
map<ll,ll>m;
void bsgs(ll a,ll b,ll p)
{
    m.clear();
    if(a%p==0 && b%p==0){printf("0\n");return;}
    if(a%p==0 && b%p!=0){printf("Orz, I cannot find x!\n");return;}
    
    ll x=b%p,s=ceil(sqrt(p));m[x]=0;
    //printf("%lld %lld\n",s,x);
    for(int i=1;i<=s;i++){x=(x*a)%p;m[x]=i;/*printf("%d %lld\n",i,x);*/}    
    ll t=pow(a,s);x=1;
    for(int i=1;i<=s;i++)
    {
        x=(x*t)%p;
        //printf("%lld ",x);
        if(m[x])
        {
            ll ans=i*s-m[x];
            printf("%lld\n",(ans%p+p)%p);
            return;
        }
    }
    printf("Orz, I cannot find x!\n");
}
int main()
{
    T=read(),K=read();
    while(T--)
    {
        y=read(),z=read(),p=read();
        if(K==1)printf("%lld\n",pow(y,z));
        if(K==2)
        {
            ll a,b,d;
            d=exgcd(y,p,a,b);
            if(z%d!=0)printf("Orz, I cannot find x!\n");
            else
            {
                ll ans=(z/d)*a,mod=p/d;
                ans=(ans%mod+mod)%mod;
                printf("%lld\n",ans%p);
            }
        }
        if(K==3)bsgs(y,z,p);
    }
    return 0;
}

 噢对了,小心特判!!

posted @ 2018-04-05 18:12 hyf20010101 阅读(...) 评论(...) 编辑 收藏