P2485 [SDOI2011]计算器(快速幂+扩欧+bsgs)

Posted zhangbuang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2485 [SDOI2011]计算器(快速幂+扩欧+bsgs)相关的知识,希望对你有一定的参考价值。

题目描述

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

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

说明

技术图片

 





 

设问题给的是 a ,b p;

 

k==1 谁都会吧 = =

 

k=2:   扩展欧几里得 设d=(a,p) ,若d !| b 无解,

当d=1; 套班子,在0到p-1上有一个解

当d!=1,  套板子,最后设 t = b/d,也即是b是gcd的几倍,然后由于x和y算出来是除了d的,所以最后x要乘t,在0到p/d-1上有一个解

 

k=3 出门左转,EXBSGS

 

 

 

  1 #include"bits/stdc++.h"
  2 using namespace std;
  3 typedef long long ll;
  4 
  5 ll work1(ll a,ll b,ll mod)
  6 {
  7   ll ans=1;ll base=a%mod;
  8   while (b){if(b&1)ans=(ans*base)%mod;b>>=1;base=base*base%mod;}return ans;
  9 }
 10 
 11 void exgcd(ll &x,ll &y,ll a,ll b)
 12 {
 13   if(b==0){x=1,y=0;return ;}
 14   exgcd(x,y,b,a%b);ll t=x; x=y;y=(t-(a/b)*y);
 15 }
 16 
 17 unordered_map <ll,ll> mp;
 18 
 19 
 20 
 21 
 22 ll bsgs(ll a,ll b,ll p)
 23 {
 24    b%=p;
 25    if(b==1)return 0; ll d; ll k=1; int cnt=0;
 26 
 27    while ((d=__gcd(a,p))^1)
 28    {
 29       if(b%d)return -1;
 30       b/=d; p/=d;cnt++;
 31       k=1ll*k*(a/d)%p;
 32       if(k==b)return cnt;
 33 
 34        // cout<<k<<" "<<a<<" "<<b<<" "<<p<<endl;
 35    }
 36 
 37 
 38 
 39    int m=sqrt(p)+1; ll kt=1;
 40    mp.clear();
 41    for (int i=0;i<m;i++)
 42    {
 43      mp[1LL*kt*b%p]=i;
 44      kt=kt*a%p;
 45 
 46    }
 47 
 48    k=k*kt%p;
 49 
 50    for (int i=1;i<=m;i++)
 51    {
 52      if(mp.find(k)!=mp.end()) return i*m-mp[k]+cnt;
 53      k=k*kt%p;
 54    }
 55 
 56    return -1;
 57 
 58 }
 59 
 60 
 61 
 62 
 63 int main()
 64 
 65 {
 66  /*  int x,y;
 67    exgcd(x,y,3,10);
 68    cout<<(x%10+10)%10;*/
 69 
 70 
 71 
 72 
 73    ll T,k; ll y,z,p;
 74    cin>>T>>k;
 75 
 76     while (T--)
 77     {  scanf("%lld%lld%lld",&y,&z,&p);
 78        if(k==1)
 79        {
 80           printf("%lld
",work1(y,z,p));
 81        }
 82        else if(k==2)
 83        {
 84           ll Gcd=__gcd(y,p); if(z%Gcd!=0)
 85           {puts("Orz, I cannot find x!");continue;}
 86            ll x1,y1; ll t=z/Gcd;
 87            exgcd(x1,y1,y,p);
 88            p=p/Gcd;
 89          // cout<<x1<<endl;
 90            printf("%lld
",1ll*((x1*z/Gcd)%p+p)%p);
 91        }
 92        else
 93        {
 94            ll ans=bsgs(y,z,p);
 95            if(ans!=-1)printf("%lld
",ans);
 96           else puts("Orz, I cannot find x!");
 97         }
 98     }
 99 
100 }

 

以上是关于P2485 [SDOI2011]计算器(快速幂+扩欧+bsgs)的主要内容,如果未能解决你的问题,请参考以下文章

P2485 [SDOI2011]计算器

P2485 [SDOI2011]计算器

BZOJ2242SDoi2011计算器 快速幂+EXGCD+BSGS

BZOJ 2242 [SDOI2011]计算器(快速幂+Exgcd+BSGS)

BZOJ_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS

[SDOI2011]计算器