码迷,mamicode.com
首页 > 其他好文 > 详细

【bzoj2242】【SDOI2011】【计算器】

时间:2015-08-04 19:21:03      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:

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,然后直接乘过去就好了。

#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");
            }
        }
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

【bzoj2242】【SDOI2011】【计算器】

标签:

原文地址:http://blog.csdn.net/fzhvampire/article/details/47279969

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!