BZOJ 2242([SDOI2011]计算器-Baby Step Giant Step第1题)

2242: [SDOI2011]计算器

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 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。

Sample Output

【样例输出1】
2
1
2
【样例输出2】
2
1
0

HINT

Source

[ Submit][ Status]

第一次写这么【高端,洋气,上档次】的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;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值