• 【bzoj2242】[SDOI2011]计算器 EXgcd+BSGS


    题目描述

    你被要求设计一个计算器完成以下三项任务:
    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)的最小非负整数。

    输入

    输入包含多组数据。

    第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。
    以下行每行包含三个正整数y,z,p,描述一个询问。

    输出

    对于每个询问,输出一行答案。对于询问类型2和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”,注意逗号与“I”之间有一个空格。

    样例输入

    【样例输入1】
    3 1
    2 1 3
    2 2 3
    2 3 3
    【样例输入2】
    3 2
    2 1 3
    2 2 3
    2 3 3

    样例输出

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


    题解

    EXgcd+BSGS

    第一问直接快速幂。

    第二问需要将xy≡z(mod p)转化为xy+tp=z,进而用EXgcd求解。

    第三问是裸的BSGS。

    根据费马小定理可知如果有解,答案一定小于p。

    设m=√p(向上取整),再设x=km+b,其中k<m,b<m。

    那么就有y^(km+b)≡z(mod p),即y^b≡z/y^km(mod p)。

    于是我们可以将所有的y^b mod p加入到map中,然后枚举k,求出z/y^km,看是否有相同的值在map中即可。

    本题特判比较多,具体详见代码。

    #include <cstdio>
    #include <cmath>
    #include <map>
    using namespace std;
    typedef long long ll;
    map<ll , ll> f;
    map<ll , ll>::iterator it;
    ll pow(ll x , ll y , ll mod)
    {
    	ll ans = 1;
    	while(y)
    	{
    		if(y & 1) ans = ans * x % mod;
    		x = x * x % mod , y >>= 1;
    	}
    	return ans;
    }
    ll gcd(ll a , ll b)
    {
    	return b ? gcd(b , a % b) : a;
    }
    void exgcd(ll a , ll b , ll &x , ll &y)
    {
    	if(!b)
    	{
    		x = 1 , y = 0;
    		return;
    	}
    	exgcd(b , a % b , x , y);
    	ll t = x;
    	x = y , y = t - a / b * y;
    }
    int main()
    {
    	int T , k;
    	scanf("%d%d" , &T , &k);
    	while(T -- )
    	{
    		ll y , z , p;
    		scanf("%lld%lld%lld" , &y , &z , &p);
    		switch(k)
    		{
    			case 1: printf("%lld
    " , pow(y , z , p)); break;
    			case 2:
    			{
    				y %= p , z %= p; 
    				ll t = gcd(y , p) , x1 , x2;
    				if(z % t != 0)
    				{
    					printf("Orz, I cannot find x!
    ");
    					break;
    				}
    				y /= t , p /= t , z /= t , exgcd(y , p , x1 , x2) , x1 *= z;
    				while(x1 < 0) x1 += p;
    				while(x1 - p >= 0) x1 -= p;
    				printf("%lld
    " , x1);
    				break;
    			}
    			default:
    			{
    				y %= p , z %= p; 
    				if(!y)
    				{
    					if(!z) printf("1
    ");
    					else printf("Orz, I cannot find x!
    ");
    					break;
    				}
    				ll m = (ll)ceil(sqrt(p)) , i , flag = 0 , t = 1 , temp;
    				f.clear();
    				for(i = 0 ; i < m ; i ++ )
    				{
    					if(f.find(t) == f.end()) f[t] = i;
    					t = t * y % p;
    				}
    				temp = pow(y , p - m - 1 , p) , t = 1;
    				for(i = 0 ; i <= m ; i ++ )
    				{
    					it = f.find(z * t % p) , t = t * temp % p;
    					if(it != f.end())
    					{
    						printf("%lld
    " , i * m + it->second) , flag = 1;
    						break;
    					}
    				}
    				if(!flag) printf("Orz, I cannot find x!
    ");
    			}
    		}
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    C#值类型与引用类型
    Eclipse中JSP生成的类文件存放在哪
    java发起HTTP请求的共用类
    .net汉字转字母
    常用 C#操作字符串方法
    MYSQL整理的语法
    CSS基础篇
    JavaScript基础篇
    jquery操作select(增加,删除,清空)
    Aspose.Words 的使用 Aspose.Total_for_.NET
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6999367.html
Copyright © 2020-2023  润新知