1467: Pku3243 clever Y

1467: Pku3243 clever Y

Time Limit: 4 Sec   Memory Limit: 64 MB
Submit: 254   Solved: 142
[ Submit][ Status][ Discuss]

Description

小Y发现,数学中有一个很有趣的式子: X^Y mod Z = K 给出X、Y、Z,我们都知道如何很快的计算K。但是如果给出X、Z、K,你是否知道如何快速的计算Y呢?

Input

本题由多组数据(不超过20组),每组测试数据包含一行三个整数X、Z、K(0 <= X, Z, K <= 109)。 输入文件一行由三个空格隔开的0结尾。

Output

对于每组数据:如果无解则输出一行No Solution,否则输出一行一个整数Y(0 <= Y < Z),使得其满足XY mod Z = K,如果有多个解输出最小的一个Y。

Sample Input

5 58 33
2 4 3
0 0 0

Sample Output

9
No Solution

HINT

Source

ghy

[ Submit][ Status][ Discuss]

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

typedef long long LL;
const int Mod = 999983;

struct data{
	int Num,val; data(){}
	data(int Num,int val): Num(Num),val(val){}
};

stack <int> s;
vector <data> v[Mod];

int Mul(const LL &x,const LL &y,const LL &p) {return x * y % p;}

int ksm(int x,int y,int p)
{
	int ret = 1;
	for (; y; y >>= 1)
	{
		if (y & 1) ret = Mul(ret,x,p);
		x = Mul(x,x,p);
	}
	return ret;
}

void Extend_Gcd(LL a,LL &x,LL b,LL &y,LL &g)
{
	if (!b) {g = a; x = 1; y = 0; return;}
	Extend_Gcd(b,y,a % b,x,g); y -= a / b * x;
}

int GetInv(int a,int p)
{
	LL x,y,g;
	Extend_Gcd(a,x,p,y,g);
	return (x % p + p) % p;
}

void Clear()
{
	while (!s.empty())
		v[s.top()].clear(),s.pop();
}

void Insert(int val,int Num)
{
	int pos = val % Mod;
	if (!v[pos].size()) s.push(pos);
	for (int i = 0; i < v[pos].size(); i++)
		if (v[pos][i].val == val) return;
	v[pos].push_back(data(Num,val));
}

int Search(int val)
{
	int pos = val % Mod;
	for (int i = 0; i < v[pos].size(); i++)
		if (v[pos][i].val == val) return v[pos][i].Num;
	return -1;
}

void BSGS(int y,int p,int z)
{
	Clear(); LL x,Y,g,tmp = 1;
	int cnt = 0,_p = p; y %= p; z %= p;
	if (y == z) {puts("1"); return;} 
	if (z == 1) {puts("0"); return;} //ÌØÅÐAns == 1 || Ans == 0 
	for (;;)
	{
		Extend_Gcd(y,x,_p,Y,g);
		if (g == 1) break; ++cnt;
		if (z % g != 0) {puts("No Solution"); return;}
		tmp = Mul(tmp,y / g,p); z /= g; _p /= g;
	}
	p = _p; tmp = GetInv(tmp,p); z = Mul(z,tmp,p);
	int Sqrt = sqrt(p); tmp = ksm(y,Sqrt,p);
	for (int now = 1 % p,tot = 0; tot <= Sqrt; now = Mul(now,y,p),tot++) Insert(now,tot); //×¢ÒâÄ£Êý¿ÉÄÜΪ1£¬ËùÒÔÆðʼµãÊÇ1 %£ð 
	for (int i = 0,now = 1; i <= Sqrt + 3; now = Mul(now,tmp,p),i++) // ö¾Ù´ÎÊýÂÔ´óÓÚSqrt 
	{
		int Inv = GetInv(now,p);
		int ret = Search(Mul(Inv,z,p));
		if (ret == -1) continue;
		printf("%d\n",i * Sqrt + ret + cnt); return;
	}
	puts("No Solution");
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	for (;;)
	{
		int x,z,k; scanf("%d%d%d",&x,&z,&k);
		if (!x && !z && !k) break;
		if (!z) {puts("No Solution"); continue;}
		if (!x) {puts(!k ? "0" : "No Solution"); continue;}
		BSGS(x,z,k);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值