【BZOJ2242】【SDoi2011】计算器 快速幂+EXGCD+BSGS

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

HINT

 

Source

Solution:第一问快速幂
      第二问EXGCD
      第三问BSGS
BSGS(Baby Step Giant Step)网上介绍的很详细了,但是我令x=im-j这样就不用求逆元辣,相应的为了不出现负数是i从1开始到m枚举,则j从1到m枚举,因为可以等于m,j就不需要从0开始啦.。
另:一开始在CV上测,用了puts试试,忘了自带换行在CV上过了,然而在BZOJ PE了233
 1  
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cmath>
 5 #include <map>
 6 #define ll long long 
 7 using namespace std;
 8 ll y,z,p;
 9  
10 ll fast_pow(ll y,ll z,ll p)
11 {
12     ll ans=1;
13     while (z)
14     {
15         if (z&1)    ans=ans*y%p;
16         y=y*y%p;
17         z>>=1;
18     }
19     return ans;
20 }
21  
22 ll gcd(ll a,ll b)
23 {return b==0?a:gcd(b,a%b);}
24  
25 void ex_gcd(ll a,ll b,ll &x,ll &y)
26 {
27     if (!b) {x=1;y=0;return;}
28     ex_gcd(b,a%b,x,y);
29     ll t=x; x=y; y=t-a/b*y; 
30 }
31  
32 void solve1()
33 {
34     printf("%lld\n",fast_pow(y,z,p));
35 }
36  
37 void solve2()
38 {
39     ll d=gcd(y,p);
40     if (z%d)    {printf("Orz, I cannot find x!\n");return;}
41     y/=d; z/=d;
42     ll a,b;
43     ex_gcd(y,p,a,b);
44     a=a*z%p;
45     while (a<0)  a+=p;
46     printf("%lld\n",a);
47 }
48  
49 void solve3()
50 {
51     y%=p,z%=p;
52     if (!y && !z)   {puts("1"); return;}
53     if (!y) {printf("Orz, I cannot find x!\n");return;}
54     map<ll,ll> mp;
55     mp.clear();
56     ll m=ceil(sqrt(p));
57     ll t=fast_pow(y,m,p),k=z%p;//直接m即可 
58     for (int i=0;i<m;i++)
59     {
60         if (!mp[k]) if (i) mp[k]=i;//注意变量,及时订正。 
61                     else mp[k]=-1;
62         k=k*y%p;
63     }
64     k=1;
65     for (int i=0;i<m;i++)
66     {
67         if (mp[k])//注意!mp与mp的判断 
68         {
69             if (mp[k]==-1)  mp[k]=0;
70             printf("%lld\n",i*m-mp[k]);
71             return;
72         }
73         k=k*t%p;
74     }
75     printf("Orz, I cannot find x!\n");//各种傻 
76 }
77  
78 int main()
79 {
80     int T,t;
81     scanf("%d%d",&T,&t);
82     while (T--)
83     {
84         scanf("%lld%lld%lld",&y,&z,&p);
85         if (t==1)   solve1();
86         if (t==2)   solve2();
87         if (t==3)   solve3();
88     }
89 }
View Code

 

—Anime Otaku Save The World.
posted @ 2016-02-28 19:49  DMoon  阅读(179)  评论(0编辑  收藏  举报