2242: [SDOI2011]计算器
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 744 Solved: 289
[ Submit][ Status]
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。
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
2
1
2
【样例输出2】
2
1
0
HINT
Source
第一次写这么【高端,洋气,上档次】的Hash
为特例苦调一下午……数论题写的根数据结构题还久……
Baby Step Giant Step+离散对数 可A此题
问:y^x=b (mod p) 求x
Hash暴力做法(和双向广搜类似)
事先处理出y^0,y^1....y^m
y^(im+j)= b (mod p)
y^im= b*y^j (mod p) 尽情暴力
注意特判:我参考的是lyd的程序
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cctype>
#include<map>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MEM(a) memset(a,0,sizeof(a))
#define MEMI(a) memset(a,127,sizeof(a))
#define MEMi(a) memset(a,128,sizeof(a))
#define INF (2139062143)
#define MAXT (10+10)
#define MAXY (1000000000)
#define MAXN (1865060)
typedef long long ll;
ll gcd(ll a,ll b){if (!b) return a;return gcd(b,a%b);}
ll exgcd(ll a,ll b,ll &x, ll &y)
{
if (!b) {x=1,y=0;return a;}
ll g=exgcd(b,a%b,x,y);
ll t=x;x=y;y=t-a/b*y;
return g;
}
ll pow2(ll a,int b,ll F)
{
if (b==0) return 1;
if (b==1) return a;
ll c=pow2(a,b/2,F);
c=c*c%F;
if (b&1) c=c*a%F;
return c;
}
void Modp(ll a,ll b,ll p)
{
ll x,y;
ll g=exgcd(a,p,x,y),d;
if (b%g) {puts("Orz, I cannot find x!");return;}
d=b/g;x*=d,y*=d;
x=(x+abs(x)/p*p+p)%p;
printf("%lld\n",x);
}
int h[MAXN]={0};
ll hnum[MAXN]={0};
int hash(ll x)
{
int i=x%MAXN;
while (h[i]&&hnum[i]!=x) i=(i+1)%MAXN;
hnum[i]=x;
return i;
}
void babystep(ll a,ll b,int p)
{
int m=sqrt(p);while (m*m<p) m++;
ll res=b,ans=-1;
ll uni=pow2(a,m,p);
if (!uni) if (!b) ans=1;else ans=-1; //特判
else
{
Rep(i,m+1)
{
int t=hash(res);
h[t]=i+1;
res=(res*a)%p;
}
res=uni;
For(i,m+1)
{
int t=hash(res);
if (h[t]) {ans=i*m-(h[t]-1);break;}else hnum[t]=0;
res=res*uni%p;
}
res=b;
Rep(i,MAXN) h[i]=hnum[i]=0;
}
if (ans>-1) printf("%lld\n",ans);
else puts("Orz, I cannot find x!");
}
int main()
{
// freopen("bzoj2242.in","r",stdin);
// freopen("bzoj2242.out","w",stdout);
int T,p,x,y,z;
while (scanf("%d%d",&T,&p)==2)
{
if (p==1)
{
For(i,T)
{
scanf("%d%d%d",&x,&y,&z);
printf("%lld\n",pow2(x,y,z));
}
}
else if (p==2)
{
For(i,T)
{
scanf("%d%d%d",&x,&y,&z);
Modp(x,y%z,z);
}
}
else
{
For(i,T)
{
scanf("%d%d%d",&x,&y,&z);
babystep(x,y%z,z);
}
}
}
return 0;
}