【BZOJ2242/SDOI2011】计算器

                                          2242: [SDOI2011]计算器

                                                                       Time Limit: 10 Sec  Memory Limit: 512 MB
                                                                                    Submit: 5618  Solved: 2193

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,P为质数,1<=T<=10。

Sample Output

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

 

解析:

       三个模板。。。

       操作一:快速幂

       操作二:扩展欧几里得

       操作三:BSGS

 

代码:

#include <bits/stdc++.h>
#include <tr1/unordered_map>
#define int long long
using namespace std;
using namespace std::tr1;

const int mod=1e6+7;
int a,b,p,t,flag,gcd,x,y;

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}
inline void print(int x)
{
	if(x>9) print(x/10);
	putchar('0'+x%10);
}

inline int solve1(int a,int b,int p)
{
	int ans=1;
	while(b)
	{
	  if(b&1) ans=(ans*a)%p;
	  b>>=1;
	  a=(a*a)%p;
	}
	return ans;
}

inline int exgcd(int a,int b)
{
	if(!b) x=1,y=0,gcd=a;
	else
	{
	  exgcd(b,a%b);
	  int t=x;
	  x=y;
	  y=t-a/b*x;
	}
}

inline void solve2()
{
	exgcd(a,p);
	if(b%gcd) {cout<<"Orz, I cannot find x!\n";return;}
	x=(x*(b/gcd)%p+p)%p;
	print(x),putchar('\n');
}

inline int BSGS()
{
	unordered_map<int,int>Hash;
	int t=(int)sqrt(p)+1;
	for(int i=0;i<t;i++)
	{
	  int val=b*solve1(a,i,p)%p;
	  Hash[val]=i;
	}
	a=solve1(a,t,p);
	if(!a) return !b ? 1 : -1;
	for(int i=1;i<=t;i++)
	{
	  int val=solve1(a,i,p);
	  int j=Hash.find(val) == Hash.end() ? -1 : Hash[val];
	  if(j>=0 && i*t-j>=0) return i*t-j;
	}
	return -1;
}

inline void solve3()
{
	int ans=BSGS();
	if(!(~ans)) {cout<<"Orz, I cannot find x!\n";return;}
	else print(ans),putchar('\n');
}

signed main()
{
	t=get_int(),flag=get_int();
	if(flag==1) for(int i=1;i<=t;i++) a=get_int(),b=get_int(),p=get_int(),print(solve1(a,b,p)),putchar('\n');
	if(flag==2) for(int i=1;i<=t;i++)
	{
	  a=get_int(),b=get_int(),p=get_int();
	  solve2();
	}
	if(flag==3) for(int i=1;i<=t;i++)
	{
	  a=get_int(),b=get_int(),p=get_int();
	  solve3();
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值