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
第一轮day1
第一个快速幂,没意思。
第二个exgcd,在这:【poj1061】青蛙的约会 exgcd解同余方程
第三个是刚学的BSGS…
BSGS,就是大步小步法,用来解这个方程:
令 x=i*m+j ,则上面的式子就变为:
于是可以枚举 Aj ,然后算出 Am 的逆元,然后枚举它的i次方再乘b,查表即可。
因为x最大不会超过C,所以 m=ceil(sqrt(C)) 最优,可以结合分块思想去想。
其实也相当于中途相遇法。
我也不知道如何证明正确性……几个小时之前证了一下现在发现不大对……不过确实是A掉了…
关于 Am 的逆元,因为费马小定理 An−1≡1(modn) ,所以 Am∗An−1−m≡1(modn) ,所以 Am 的逆元是 An−1−m 。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
const int SZ = 1000010;
const LL MOD = 1000007;
LL ksm(LL a,LL b,LL mod)
{
LL ans = 1;
while(b)
{
if(b & 1) ans = ((ans % mod) * (a % mod)) % mod;
a = ((a % mod) * (a % mod)) % mod;
b >>= 1;
}
return ans;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b == 0)
{
x = 1; y = 0;
return a;
}
LL d = exgcd(b,a % b,x,y);
LL t = x; x = y; y = t - a / b * y;
return d;
}
LL get_exgcd(LL a,LL b,LL c) //ax+by=c
{
LL x,y;
LL d = exgcd(a,b,x,y);
if(c % d) return -1;
return ((x * (c / d)) % (b / d) + (b / d)) % (b / d);
}
map<LL,LL> hash;
LL BSGS(LL a,LL b,LL mod) //a^x = b (% mod)
{
a %= mod; b %= mod;
if(a == 0 && b == 0) return 1;
else if(a == 0) return -1;
hash.clear();
LL m = ceil(sqrt(mod));
LL amni = ksm(a,mod - m - 1,mod);
LL t = 1;
hash[t] = 0;
for(int i = 1;i < m;i ++)
{
t = (t * a) % mod;
if(t != 1 && !hash[t])
hash[t] = i;
}
for(int i = 0;i <= m - 1;i ++)
{
LL ans = hash[b];
if(b == 1 || ans)
{
return i * m + ans;
}
b = (b * amni) % mod;
}
return -1;
}
int main()
{
int T,k;
scanf("%d%d",&T,&k);
while(T --)
{
LL a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
if(k == 1)
{
printf("%lld\n",ksm(a,b,c));
}
else if(k == 2)
{
LL ans = get_exgcd(a,c,b);
if(ans == -1) puts("Orz, I cannot find x!");
else printf("%lld\n",ans);
}
else
{
LL ans = BSGS(a,b,c);
if(ans == -1) puts("Orz, I cannot find x!");
else printf("%lld\n",ans);
}
}
return 0;
}
/*
10 3
1000052719 255392610 79791109
146324954 14948940 73162477
703874049 508100543 1037977027
260580983 889231132 496040033
691085033 402703206 539487719
752770845 539141408 817774367
974839853 763383053 22685989
855218194 362010502 198721379
900451466 1064373182 697990169
13892212 176820695 856980737
*/