快速幂 扩欧 扩BSGS 三合一板子题

[SDOI2011]计算器

题目描述

你被要求设计一个计算器完成以下三项任务:

1、给定y、z、p,计算y^z mod p 的值;

2、给定y、z、p,计算满足xy ≡z(mod p)的最小非负整数x;

3、给定y、z、p,计算满足y^x ≡z(mod p)的最小非负整数x。

为了拿到奖品,全力以赴吧!

输入输出格式

输入格式:

输入文件calc.in 包含多组数据。

第一行包含两个正整数T、K,分别表示数据组数和询问类型(对于一个测试点内的所有数

据,询问类型相同)。

以下T 行每行包含三个正整数y、z、p,描述一个询问。

输出格式:

输出文件calc.out 包括T 行.

对于每个询问,输出一行答案。

对于询问类型2 和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”。

输入输出样例

输入样例#1: 复制
3 1
2 1 3
2 2 3
2 3 3
输出样例#1: 复制
2
1
2
输入样例#2: 复制
3 2
2 1 3
2 2 3
2 3 3
输出样例#2: 复制
2
1
0
输入样例#3: 复制
4 3
2 1 3
2 2 3
2 3 3
2 4 3
输出样例#3: 复制
0
1
Orz, I cannot find x!
0

说明

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#define ll long long 
using namespace std;
int T,k;
ll a,z,p;
map<ll,int>ha;
ll pow(ll a,ll x)
{
    ll ans=1;
    while(x)
    {
    if(x&1)ans=(ans*a)%p;
    a=(a*a)%p;
    x>>=1;
    }
    return ans%p;
}
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    ll d=a;
    if(!b)x=1,y=0;
    else d=exgcd(b,a%b,y,x),y-=(a/b)*x;
    return d;
}
ll get(ll a,ll b)
{
    ll x=0,y=0;
    ll d=exgcd(a,b,x,y);
    if(z%d)return -1;
    x*=(z/d);
    return (x%b+b)%b;
}
ll exbsgs(int a,int b,int x)
{
    ha.clear();
    a%=x,b%=x;ll m=ceil(sqrt((double)x));
    if(b==1)return 0;
    ll tmp=1,cnt=0,D=1;
    while((tmp=gcd(a,x))!=1)
    {
    if(b%tmp)return -1;
    cnt++,b/=tmp,x/=tmp,D=(D*(a/tmp))%x;
    }
    ha[b%x]=0;ll q=1;
    for(int i=1;i<=m;i++)q=(q*a)%x,ha[q*b%x]=i;
    for(int i=1;i<=m;i++)
    {
    D=(D*q)%x;
    if(ha[D]){ll s=i*m-ha[D]+cnt;return (s%x+x)%x;}
    }
    return -1;
}
int main()
{
    freopen("three.in","r",stdin);
    freopen("three.out","w",stdout);
    scanf("%d%d",&T,&k);
    for(int i=1;i<=T;i++)
    {
    scanf("%lld%lld%lld",&a,&z,&p);
    if(k==1)printf("%lld
",pow(a,z));
    else if(k==2)
    {
        ll ans=get(a,p);
        if(ans==-1)puts("Orz, I cannot find x!");
        else printf("%lld
",ans);
    }
    else
    {
        ll ans=exbsgs(a,z,p);
        if(ans==-1)puts("Orz, I cannot find x!");
        else printf("%lld
",ans);
    }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lxykk/p/8343453.html