题目p2109
From Tyvj Guest☆【bzoj2242】计算器
背景 Background
此系列问题为数论专题
具体参考博文
http://blog.csdn.net/chty2018/article/details/53432272
描述 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 Format
输入包含多组数据。
第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。
以下行每行包含三个正整数y,z,p,描述一个询问。
输出格式 Output Format
对于每个询问,输出一行答案。对于询问类型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
【样例输入3】
4 3
2 1 3
2 2 3
2 3 3
2 4 3
样例输出 Sample Output
【样例输出1】
2
1
2
【样例输出2】
2
1
0
【样例输出3】
0
1
Orz, I cannot find x!
0
时间限制 Time Limitation
1s
注释 Hint
【数据规模和约定】
对于20%的数据,K=1;
对于35%的数据,K=2;
对于45%的数据,K=3;
对于100%的数据,1≤y,z,P≤〖10〗^9,P为质数,1≤T≤10。
来源 Source
【bzoj2242】计算器
题面,数据来自宋逸群
题解
第一问快速幂
第二问exgcd
第三问BSGS,好麻烦我就先略
为啥叫baby step giant step,我其实不是很懂
卓神说这是meet in the middle的一种运用
求
设
用费马小定理显然可得
设其为
把
放入hash或者map
然后枚举k,查询
显然
取
复杂度比较优秀。。
转自hzwer
然而我现在还是不会离散对数。
代码
这个学习黄学长的代码的评测结果:
Result | Memory | Time | Language | Code_Length | Submit_Time |
---|---|---|---|---|---|
Accepted | 3288 kb | 2012 ms | C++/Edit | 2158 B | 2019-01-18 16:23:49 |
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int f=1,x=0;
char ch=getchar();
while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
return x*f;
}
/////////////////////////////////////////////////////////////////////////////
//快速幂
int solve1(ll y,int z,int p)
{
y%=p;
ll ans=1;
for (int i=z; i; i>>=1,y=y*y%p)
if (i&1)
ans=ans*y%p;
return ans;
}
/////////////////////////////////////////////////////////////////////////////
//Exgcd
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
void exgcd(int a,int b,int &x,int &y)
{
if (!b)
{
x=1,y=0;
return;
}
exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
}
void solve2(int y,int z,int p)
{
p=-p;
int t=gcd(y,p);
if (z%t)
{
puts("Orz, I cannot find x!");
return ;
}
y/=t,z/=t,p/=t;
int a,b;
exgcd(y,p,a,b);
a=(ll)a*z%p;
while (a<0) a+=p;
printf("%d\n",a);
}
/////////////////////////////////////////////////////////////////////////////
//离散对数
map<int,int>mp;
void solve3(int y,int z,int p)
{
y%=p;
if (!y && !z)
{
puts("1");
return ;
}
if (!y)
{
puts("Orz, I cannot find x!");
return ;
}
mp.clear();
ll m=ceil(sqrt(p)),t=1;
mp[1]=m+1;
for (ll i=1; i<m; ++i)
{
t=t*y%p;
if (!mp[t])
mp[t]=i;
}
ll tmp=solve1(y,p-m-1,p),inv=1;
for (ll k=0; k<m; ++k)
{
int i=mp[z*inv%p];
if (i)
{
if (i==m+1) i=0;
printf("%lld\n",k*m+i);
return;
}
inv=inv*tmp%p;
}
puts("Orz, I cannot find x!");
}
/////////////////////////////////////////////////////////////////////////////
int main()
{
int T=read(),K=read();
while (T--)
{
int y=read(),z=read(),p=read();
if (K==1)
printf("%d\n",solve1(y,z,p));
else if (K==2)
solve2(y,z,p);
else
solve3(y,z,p);
}
return 0;
}
下面的代码转自大神yyb
Result | Memory | Time | Language | Code_Length | Submit_Time |
---|---|---|---|---|---|
Accepted | 13408 kb | 152 ms | C++/Edit | 2297 B | 2019-01-18 14:41:52 |
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
const int HashMod=100007;
inline int read() {
RG int x=0,t=1;
RG char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') t=-1,ch=getchar();
while (ch<='9'&&ch>='0') x=x*10+ch-48,ch=getchar();
return x*t;
}
int fpow(int a,int b,int MOD) {
int s=1;
while (b) {
if (b&1)
s=1ll*s*a%MOD;
a=1ll*a*a%MOD;
b>>=1;
}
return s;
}
void NoAnswer() {
puts("Orz, I cannot find x!");
}
namespace Task1 {
void Solve(int y,int z,int p) {
printf("%d\n",fpow(y,z,p));
}
}
namespace Task2 {
void Solve(int y,int z,int p) {
if (y%p==0&&z%p)
NoAnswer();
else
printf("%lld\n",1ll*fpow(y,p-2,p)*z%p);
}
}
namespace Task3 {
struct HashTable {
struct Line {
int u,v,next;
} e[1000000];
int h[HashMod],cnt;
void Add(int u,int v,int w) {
e[++cnt]=(Line) {
w,v,h[u]
};
h[u]=cnt;
}
void Clear() {
memset(h,0,sizeof(h));
cnt=0;
}
void Hash(int x,int k) {
int s=x%HashMod;
Add(s,k,x);
}
int Query(int x) {
int s=x%HashMod;
for (int i=h[s]; i; i=e[i].next)
if (e[i].u==x)
return e[i].v;
return -1;
}
} Hash;
void Solve(int y,int z,int p) {
if (y%p==0) {
NoAnswer();
return;
}
y%=p;
z%=p;
if (z==1) {
puts("0");
return;
}
int m=sqrt(p)+1;
Hash.Clear();
for (RG int i=0,t=z; i<m; ++i,t=1ll*t*y%p)
Hash.Hash(t,i);
for (RG int i=1,tt=fpow(y,m,p),t=tt; i<=m+1; ++i,t=1ll*t*tt%p) {
int k=Hash.Query(t);
if (k==-1) continue;
printf("%d\n",i*m-k);
return;
}
NoAnswer();
}
}
int main() {
int T=read(),K=read();
while(T--) {
int y=read(),z=read(),p=read();
if (K==1) Task1::Solve(y,z,p);
if (K==2) Task2::Solve(y,z,p);
if (K==3) Task3::Solve(y,z,p);
}
return 0;
}