您的位置:首页 > 其它

【bzoj2242】【SDOI2011】【计算器】

2015-08-12 14:59 357 查看

2242: [SDOI2011]计算器

Time Limit: 10 Sec Memory Limit: 512 MB

Submit: 2032 Solved: 791

[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

①:直接快速幂就好了。

②:扩展欧几里得。

③:BSGS。

什么是BSGS呢?

他就是来解决③这种问题的。

我们要求y^x=z(mod p)

这里的x<=p-1。为什么呢?

因为由费马小定理可之当x=p-1时z=1。当p=0时z=1。

所以在小于p之内一定会出现循环节。

我们可以转化成求

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

y^(i*m)=z * ni(y^j) (mod p) ni(x)表示x的逆元。

这里的m=sprt(p)。

我们只需要先预处理出y^j(1<=j<=sprt(p))

然后对于左边,我们枚举i,如果有符合的就输出,没有的话就说明不存在x。

但其实我们并不需要去求逆元。

我们只需要将i * m+j改成i * m - j,然后直接乘过去就好了。

[code]#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath> 
#include<map>
using namespace std;
#define LL long long 
int t,k;
map<LL,LL> mp;
LL quickpow(LL y,LL z,LL p)
{
    LL ans=1;
    while(z){
        if(z&1) ans=ans*y%p;
        z>>=1;
        y=y*y%p;
    }
    return ans;
}
int main()
{
    LL ans,y,z,p;
    scanf("%d%d",&t,&k);
    while(t--){
        scanf("%lld%lld%lld",&y,&z,&p);
        if(k==1) printf("%lld\n",quickpow(y,z,p));
        if(k==2){
            LL ni=quickpow(y,p-2,p);
            ans=ni*z%p;
            if(ans*y%p==z%p) printf("%lld\n",ans);
            else printf("Orz, I cannot find x!\n");
        }
        if(k==3){
            bool f=false;
            LL i,j=1,m=sqrt(p);
            y%=p,z%=p;
            if(!y) printf("Orz, I cannot find x!\n");
            else{
                mp.clear();
                mp[1]=0;
                for(i=1;i<m;++i){
                    j=j*y%p;
                    if(!mp[j*z%p]) mp[j*z%p]=i; 
                }
                j=1;
                LL tmp=quickpow(y,m,p);
                for(i=0;i<m;++i){
                    if(mp[j]){
                        f=true;
                        printf("%lld\n",i*m-mp[j]);
                        break;
                    }
                    j=j*tmp%p;      
                }
                if(!f) printf("Orz, I cannot find x!\n");
            }
        }
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: