BZOJ-2242 (几种数论模板)

73 篇文章 0 订阅

题目

2242: [SDOI2011]计算器
Time Limit: 10 Sec Memory Limit: 512 MB
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,描述一个询问。

对于100%的数据,1<=y,z,p<=10^9,为质数,1<=T<=10。

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

Sample Output

【样例输出1】

2
1
2

【样例输出2】

2
1
0

分析

  • 第一种询问,直接快速幂;
  • 第二种,x=(Y/1)*Z,逆元一下再模一下(求出最小解);
  • 第三种,bsgs 求解即可。

程序

#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
using namespace std;
typedef long long ll;
ll m,T,K,Y,Z,P,k,F,G,ret,ss;
map <ll,ll> M;

ll ksm(ll x,ll y){
    for (ret=1; y; y>>=1,x=(x*x)%P)
        if (y&1) ret=(ret*x)%P;
    return ret;
}

int main(){
    scanf("%lld%lld",&T,&K);
    if (K==1){
        for (; T--; ){
            scanf("%lld%lld%lld",&Y,&Z,&P);
            printf("%lld\n",ksm(Y,Z));
        }
        return 0;
    }
    if (K==2){
        for (; T--; ){
            scanf("%lld%lld%lld",&Y,&Z,&P);
            Y%=P,Z%=P;
            if (Y==0 && Z!=0){puts("Orz, I cannot find x!"); continue;}
            k=(ksm(Y,P-2)*Z)%P;
            printf("%lld\n",k);
        }
        return 0;
    }
        for (; T--; ){
            scanf("%lld%lld%lld",&Y,&Z,&P);
            Y%=P,Z%=P;          //这里要模够 
            if (!Y && !Z){puts("1"); continue;}
            if (!Y){puts("Orz, I cannot find x!"); continue;}
            M.clear();
            m=ceil(sqrt(P));
            ss=Z%P; M[ss]=0;
            for (ll i=1; i<=m; i++){
                ss=(ss*Y)%P;
                if (!M[ss]) M[ss]=i;
            }
            G=ksm(Y,m);
            F=0,ss=1;
            for (ll i=1; i<=m && !F; i++){
                ss=(ss*G)%P;
                if (M[ss]){
                    ss=(i*m-M[ss]);
                    printf("%lld\n",(ss%P+P)%P);
                    F=1;
                    break;
                }
            }
            if (!F) puts("Orz, I cannot find x!");
        }
    return 0;
}

提示

  • 打注释那里要模,不然过不了,不知道为什么。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值