bzoj2242【sdoi2011】计算器

2242: [SDOI2011]计算器

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 1700   Solved: 660
[ Submit][ Status][ Discuss]

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



题解:

① 快速幂

② 乘法逆元费马小定理:若p是质数,且a和p互质,则a^(p-1)%p=1。所以a的乘法逆元为a^(p-2)。所以最终结果为a^(p-2)*z%p。

③ BSGS算法。先把x=i*m+j,其中m=ceil(sqrt(p))。这样原式就变为y^(i*m+j)=z(mod p),再变为y^j=z*y^(-m*i) (mod p)。先循环j=0-(p-1),把(y^j,j)加入hash表中。然后我们再枚举等号右边,从hash表中找看看有没有,有的话就得到了一组i j,x=i*m+j,得到的这个就是正确解。y^(-m*i)相当于1/(y^(m*i)),这时候我们就要求逆元。



代码:

<span style="font-size:18px;">#include<iostream>
#include<math.h>
#include<map>
#include<cstdio>
#define LL long long
using namespace std;
map<LL,LL> mp;
LL power(LL y,LL x,LL p)
{
	LL tmp,ans;
	if (x==0) return 1;
	if (x==1) return(y%p);
	tmp=power(y,x/2,p);
	ans=tmp*tmp%p;
	if (x%2==1) ans=ans*y%p;
	return ans;
}
void bsgs(LL a,LL b,LL p)
{
	LL m=(LL)ceil(sqrt(p));
	LL now,tmp,x;
	mp.clear();
	mp[1]=0;
	now=1;
	for (int i=1; i<m; i++)
	{
		now=(now*a)%p;
		if (!mp.count(now)) mp[now]=i;
	}
	tmp=power(a,p-m-1,p);
	x=b;
	bool flag=false;
	for (int i=0; i<m; i++)
	{
		if (mp.count(x))
		{
			printf("%lld\n",m*i+mp[x]);
			flag=true;
			break;
		}
		x=(x*tmp)%p;
	}
	if (!flag) printf("Orz, I cannot find x!\n");
}
int main()
{
	int i,t,k;
	LL y,z,p;
	scanf("%d%d",&t,&k);
	for (i=1; i<=t; i++)
	{
		scanf("%lld%lld%lld",&y,&z,&p);
		if (k==1)
		{
			printf("%lld\n",power(y,z,p));
			continue;
		}
		y%=p;
		z%=p;
		if (!y&&z)
		{
			printf("Orz, I cannot find x!\n");
			continue;
		}
		if (k==2)
		{
			if (!y) printf("%d\n",0);
			else printf("%lld\n",power(y,p-2,p)*z%p); 
		}
		if (k==3)
		{
			if (!y) printf("%d\n",1);
			else bsgs(y,z,p);
		}
	}
	return 0;
} 
//Written by aap</span>



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值