【数学 BSGS】bzoj2242: [SDOI2011]计算器

数论的板子集合……

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”之间有一个空格。

题目分析

第一个问题:快速幂解决

第二个问题:1.转为exgcd问题   2.直接$x=Z*y^{-1}$

第三个问题:BSGS

BSGS是引入分块的思想解决形如$A^x≡B(mod\,C) C为素数$的问题(至于C不是素数就是exBSGS的范畴了)

具体来说,就是记$size=\sqrt C$,$x=i*size-j \, (0≤j<\sqrt C)$,于是式子就成了$A^{i*size}≡A^j*B$的形式。而右边这个东西是可以预处理出来放在hash表里的,这样在$\sqrt C$枚举$i$的过程中,就可以$O(1)/O(log \, n)$判断是否有相应的j了。

这类思想挺妙的,应该可以迁移到其他地方。

 

 1 #include<bits/stdc++.h>
 2 typedef long long ll;
 3 
 4 int T,k;
 5 ll x,y,p,w,z,d,cir;
 6 std::map<ll, int> mp;
 7 
 8 ll qmi(ll a, ll b)
 9 {
10     ll ret = 1;
11     for (a%=p; b; b>>=1, a=a*a%p)
12         if (b&1) ret = ret*a%p;
13     return ret;
14 }
15 ll gcd(ll a, ll b){return !b?a:gcd(b, a%b);}
16 void exgcd(ll a, ll b, ll &x, ll &y)
17 {
18     if (!b){
19         x = 1, y = 0;
20         return;
21     }
22     exgcd(b, a%b, y, x), y -= a/b*x;
23 }
24 ll BSGS(ll a, ll b, ll p)
25 {
26     if (((!b)&&(!a))) return 1;
27     if ((!a)&&b) return -1;
28     if (b==1) return 0;
29     ll size = ceil(sqrt(p)), bse = 1;
30     mp.clear();
31     for (int i=0; i<size; i++)
32     {
33         mp[bse*b%p] = i;
34         bse = bse*a%p;
35     }
36     for (ll i=0, now=1; i<=p; i+=size, now = now*bse%p)
37         if (mp.count(now)) return ((i-mp[now])%p+p)%p;
38     return -1;
39 }
40 int main()
41 {
42     for (scanf("%d%d",&T,&k); T; --T)
43     {
44         scanf("%lld%lld%lld",&x,&y,&p);
45         if (k==1) printf("%lld\n",qmi(x, y));
46         if (k==2){
47             x %= p, y %= p;
48             if (!x) puts("Orz, I cannot find x!");
49             else printf("%lld\n",y*qmi(x, p-2)%p);
50         }
51         if (k==3){
52             x %= p, y %= p, d = BSGS(x, y, p);
53             if (d==-1) puts("Orz, I cannot find x!");
54             else printf("%lld\n",d);
55         }
56     }
57     return 0;
58 }

 

 

 

 

END

posted @ 2019-01-10 20:47  AntiQuality  阅读(152)  评论(0编辑  收藏  举报