【快速幂】【扩展欧几里德】【BSGS】【SDOI 2011】【bzoj 2242】计算器

2242: [SDOI2011]计算器

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 2077  Solved: 812

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

题解:

1.快速幂。
2.扩展欧几里德。
3.BSGS,大家应该都会吧。。吾不言。
不会的可以看这里——>写的好啊!

Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
using namespace std;
#define N 100100
#define LL long long
map<LL,LL> hash;
int in(){
    int x=0; char ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
LL qp(LL x,LL y,LL p){
    LL z=1;
    while (y){
        if (y&1) z=(z*x)%p;
        x=(x*x)%p; y>>=1;
    }
    return z;
}
void work1(int y,int z,int p){
    printf("%lld\n",qp(y,z,p));
}
LL gcd(LL x,LL y){
    if (!y) return x;
    return gcd(y,x%y);
}
void exgcd(LL a,LL b,LL &x,LL &y){
    if (!b){
        x=1,y=0;
        return;
    }
    exgcd(b,a%b,x,y);
    LL k=x; x=y;
    y=k-a/b*y;
}
void work2(int y,int z,int p){
    LL w=gcd(y,p);
    if (z%w){
        printf("Orz, I cannot find x!\n");
        return;
    }
    LL x,k; exgcd(y,p,x,k);
    x=x*z/w; x=(x+p)%p;
    while (x<0) x+=p;
    printf("%lld\n",x);
}
void work3(int y,int z,int p){
    y%=p,z%=p; hash.clear();
    if (!y && !z){
        printf("1\n");
        return;
    }
    if (!y){
        printf("Orz, I cannot find x!\n");
        return;
    }
    LL pp=ceil(sqrt(p)),v=qp(y,p-pp-1,p),k=1;
    hash[1]=pp+1;
    for (LL i=1; i<=pp; i++){
        k=(k*y)%p;
        if (!hash[k]) hash[k]=i;
    }
    LL ans=-1;
    for (LL i=0; i<pp; i++){
        LL j=hash[z];
        if (j){
            if (j==pp+1) j=0;
            ans=(i*pp+j);
            break;
        }
        z=(z*v)%p;
    }
    if (ans==-1) printf("Orz, I cannot find x!\n");
    else printf("%lld\n",ans);
}
int main(){
    int T=in(),k=in();
    while (T--){
        int y=in(),z=in(),p=in();
        if (k==1) work1(y,z,p);
        else if (k==2) work2(y,z,p);
        else work3(y,z,p);
    }
    return 0;
}

你可能感兴趣的:(【快速幂】【扩展欧几里德】【BSGS】【SDOI 2011】【bzoj 2242】计算器)