• [CQOI2018]破解D-H协议


    先谈一下BSGS算法(传送门)

    但是上面这位的程序实现比较繁琐,看下面这位的。
    clover_hxy这样说

    bsgs算法,又称大小步算法(某大神称拔山盖世算法)。
    主要用来解决 A^x=B(mod C)(C是质数),都是整数,已知A、B、C求x。(poj 2417 Discrete Logging)
    具体步骤如下:
    先把x=i*m-j,其中m=ceil(sqrt(C)),(ceil是向上取整)。
    这样原式就变为A^(i*m-j)=B(mod C),
    再变为A^j×B=A^(m*i) (mod C)。
    枚举j(范围0-m),将A^j×B存入hash表
    枚举i(范围1-m),从hash表中寻找第一个满足A^j×B=A^(m*i) (mod C)。
    此时x=i*m-j即为所求。
    在网上看到的其他题解大多用的是x=i*m+j,也可以做,只是会牵扯的求逆元,所以比较麻烦。使x=i*m-j就可以轻松避免这个问题了。
    那么肯定有人会有疑问为何只计算到m=ceil(sqrt(C))就可以确定答案呢?
    x=i*m-j 也就是x 的最大值不会超过p,那超过p的怎么办 ?
    有一个公式 a^(k mod p-1)=a^k (mod p) 这个公式的推导需要用到费马小定理
    k mod p-1可以看做 k-m(p-1) ,原式可化成 a^k/(a^(p-1))^m=a^k (mod p)
    根据费马小定理 a^(p-1)=1 (mod p) 其中p为质数 ,a,p 互质,可得a^k/1^m=a^k (mod p) a^k=a^k (mod p) 得证。

    分析此题

    实际上就是求 g^a = A (mod p) 中的a,于是顺利套出模板
    注意,能少用pow我们就少用,尽量减少常数。本来就用了map,到时候被卡常就尴尬了
    这题就等于模板题,没有什么特殊的需要处理

    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<ctime>
    #include<iostream>
    #include<string>
    #include<vector>
    #include<list>
    #include<deque>
    #include<stack>
    #include<queue>
    #include<map>
    #include<set>
    #include<algorithm>
    //#pragma GCC optimize(2)
    using namespace std;
    typedef long long ll;
    const int INF=0x7fffffff;
    template<class T> inline T read(T&x){
        T data=0;
    	int w=1;
        char ch=getchar();
        while(ch!='-'&&!isdigit(ch))
            ch=getchar();
        if(ch=='-')
            w=-1,ch=getchar();
        while(isdigit(ch))
            data=10*data+ch-'0',ch=getchar();
        return x=data*w;
    }
    ll g,p,bl,A,B;
    map <ll,ll> mp;
    
    int pow1(ll x,ll k){
    	ll ans=1;
    	while(k>0)
    	{
    		if(k&1)
    			ans=(ans*x)%p;
    		x=(x*x)%p;
    		k>>=1;
    	}
    	return ans;
    }
    
    void init()
    {
    	bl=ceil(sqrt(p));
    	ll cur=pow1(g,bl),ans=cur;
    	mp[ans]=bl;
    	for(ll i=2;i<=bl;++i)
    	{
    		ans=(ans*cur)%p;
    		mp[ans]=i*bl;
    	}
    }
    
    ll BSGS(ll x)
    {
    	ll j=0,cur=1;
    	for(;j<=bl;++j)
    	{
    		if(mp[(cur*A)%p])
    			return mp[(cur*A)%p]-j;
    		cur=(cur*g)%p;
    	}
    }
    
    int main()
    {
    //  freopen(".in","r",stdin);
    //  freopen(".out","w",stdout);
    	read(g);
    	read(p);
    	init();
    	ll n;
    	read(n);
    	while(n--)
    	{
    		read(A);
    		read(B);
    		printf("%lld
    ",pow1(B,BSGS(A)));
    	}
    //  fclose(stdin);
    //  fclose(stdout);
        return 0;
    }
    
    
  • 相关阅读:
    vue中 $event 的用法--获取当前父元素,子元素,兄弟元素
    vue的通信方式(二)---祖父孙三个级别的之间的隔代通信
    js获取当前页面url信息
    解决Vue刷新一瞬间出现样式未加载完或者出现Vue代码问题
    Java POI读取excel中数值精度损失
    Java读取Excel数值内容带.0或变科学计数法的解决办法
    Java专业术语
    jdbc连接数据库
    阿里云linux配置ftp服务
    mybatis批量更新表setting parameters 错误
  • 原文地址:https://www.cnblogs.com/autoint/p/9520646.html
Copyright © 2020-2023  润新知