bzoj 2242: [SDOI2011]计算器

本文介绍了一种使用C++实现的快速幂、扩展欧几里得算法(exgcd)和大步小步法(BSGS)的方法。适用于解决特定类型的数学问题,包括求幂、求逆元和离散对数等。对于快速幂,通过循环实现了高效的幂次运算;扩展欧几里得算法用于求最大公约数和特解;大步小步法则是一种解决离散对数问题的有效方法。
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<map>
  4 #include<cmath>
  5 #define ll long long
  6 using namespace std;
  7 ll T,k,y,z,p;
  8 map<int,int> mp;
  9 void exgcd(int a1,int a2,ll &x,ll &y)
 10 {
 11     if(!a2)
 12       {
 13         x=1;
 14         y=0;
 15         return;
 16       }
 17     exgcd(a2,a1%a2,x,y);
 18     int t=x;
 19     x=y;
 20     y=t-a1/a2*y;
 21 }
 22 ll gcd(ll a1,ll a2)
 23 {
 24     for(;a2;)
 25       {
 26         ll a3=a1%a2;
 27         a1=a2;
 28         a2=a3;
 29       }
 30     return a1;
 31 }
 32 ll kuai(ll y,ll z)
 33 {
 34     ll ans=1;
 35     for(;z;)
 36       {
 37         if(z%2)
 38            ans=(ans*y)%p;
 39         y=(y*y)%p;
 40         z=z/2;
 41       }
 42     return ans;
 43 }
 44 bool pan(ll y,ll z,ll p)
 45 {
 46     mp.clear();
 47     ll m=ceil(sqrt(p)),t=1;
 48     mp[1]=m+1;
 49     for(ll i=1;i<m;i++)
 50         {
 51            t=t*y%p;
 52            mp[t]=i;
 53         }
 54     ll T=kuai(y,p-m-1),ine=1;
 55     for(int k=0;k<=m;k++)
 56        {
 57            int i=mp[z*ine%p];
 58            if(i)
 59               {
 60                 if(i==m+1)
 61                   i=0;
 62                 printf("%lld\n",k*m+i);
 63                 return 1;
 64               } 
 65           ine=ine*T%p;
 66        }
 67     return 0;
 68 }
 69 int main()
 70 {
 71     scanf("%lld%lld",&T,&k);
 72     for(int i=1;i<=T;i++)
 73       {
 74         scanf("%lld%lld%lld",&y,&z,&p);
 75         if(k==1)
 76           printf("%lld\n",kuai(y,z));
 77         if(k==2)
 78           {
 79             ll x1,y1;
 80             ll t=gcd(y,p);
 81             if(z%t)
 82               {
 83                   printf("Orz, I cannot find x!\n");
 84                   continue;
 85               }
 86             y/=t;
 87             p/=t;
 88             z/=t;
 89             exgcd(y,p,x1,y1);
 90             x1=(x1*z)%p;
 91             for(;x1<0;)
 92               x1+=p;
 93             printf("%lld\n",x1);
 94           }
 95         if(k==3) 
 96           {
 97             y%=p;
 98             z%=p;
 99             if(!y&&!z)
100               {
101                 printf("1\n");
102                 continue;
103               }
104             if(!y)
105               {
106                   printf("Orz, I cannot find x!\n");
107                   continue;
108               }
109           if(!pan(y,z,p))
110             printf("Orz, I cannot find x!\n"); 
111           }
112       }
113     return 0;
114 }

第一种情况 快速幂  第二种情况 exgcd 第三种情况 大步小步法 把x变成k*m+i,把所有的0-m次方用map存下来,然后依次累加k,直到找到一个可行的。

转载于:https://www.cnblogs.com/xydddd/p/5299317.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值