• 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 }
  • 相关阅读:
    JAVA学习笔记(十二)
    JAVA学习笔记(十)
    JAVA学习笔记(九)
    JAVA学习笔记(八)
    JAVA学习笔记(七)
    JAVA学习笔记(六)
    JAVA学习笔记(五)
    20180313 mysql
    20180306 事件监听的方法 添加事件监听和取消事件监听 轮播图
    20180302DOM通过节点关系获取元素 表单元素 下拉列表 网页换肤 操作表格 问候
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/10404534.html
Copyright © 2020-2023  润新知