zoukankan      html  css  js  c++  java
  • LA 4998简单加密游戏 —— 自相似性质&&不动点迭代

    题意

    输入正整数 $K_1$($K_1 leq 50000$),找一个12为正整数 $K_2$(不能含有前导0)使得 ${K_1}^{K_2} equiv K_2(mod {10}^{12})$。例如 $K_1=99$,$K_2=817 245 479 899 $.

    分析

    1、利用自相似性质

    如果 ${K_1}^{K_2} equiv K_2(mod {10}^{12})$,那么有 ${K_1}^{K_2 \% {10}^i} equiv K_2\% {10}^i(mod {10}^{i}), i leq 12$.

    因此可以dfs从后往前一位一位得到。

    考虑到不能含有前导0,可以求到13位,并要求大于等于1e12,答案再模1e12,这样就不会出现前导0.

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const ll mod = 1e12;
    ll K1, K2;
    ll w[15], ans;
    
    ll quickmul(ll a,ll b,ll mod) {
        ll ite = (1LL<<20)-1;
        return (a*(b>>20)%mod*(1ll<<20)%mod+a*(b&(ite))%mod)%mod;
    }
    
    ll qpow(ll a, ll b, ll mod)
    {
        ll ret = 1;
        while(b)
        {
            if(b&1)  ret = quickmul(ret, a, mod);
            a = quickmul(a, a, mod);
            b >>= 1;
        }
        return ret;
    }
    
    
    bool dfs(int cur, ll now)
    {
        if(cur == 13)
        {
            if(now >= w[12]){ans = now; return true;}
            return false;
        }
        ll W = w[cur];
        for(int i = 0;i <= 9;i++)
        {
            ll tmp = W*i + now;
            if(qpow(K1, tmp, W) == (tmp%W))
            {
                if(dfs(cur+1, tmp))  return true;
            }
        }
        return false;
    }
    
    int main()
    {
        int kase = 0;
        w[0] = 1;
        for(int i = 1;i < 15;i++)  w[i] = w[i-1] * 10;
        while(scanf("%lld", &K1) == 1 &&K1)
        {
            dfs(0, 0);
            printf("Case %d: Public Key = %lld Private Key = %lld
    ", ++kase, K1, ans%mod);
        }
    }

    2、不动点迭代

    初始时随机选取一个超过10^12的数,如1000000000007,将其代入计算,如果f(x)!=x,那么令x=f(x),如此循环,能在短时间内找出合法解。

    #include<bits/stdc++.h>
    using namespace std;
    
    
    typedef long long ll;
    const ll mod = 1e12;
    ll K1, K2;
    
    ll quickmul(ll a,ll b,ll mod) {
        ll ite = (1LL<<20)-1;
        return (a*(b>>20)%mod*(1ll<<20)%mod+a*(b&(ite))%mod)%mod;
    }
    
    ll qpow(ll a, ll b, ll mod)
    {
        ll ret = 1;
        while(b)
        {
            if(b&1)  ret = quickmul(ret, a, mod);
            a = quickmul(a, a, mod);
            b >>= 1;
        }
        return ret;
    }
    
    
    int main()
    {
        int kase = 0;
        while(scanf("%lld", &K1) == 1 &&K1)
        {
            K2 = 1e11+7;
            while(qpow(K1, K2, mod) != K2%mod)  K2 = qpow(K1, K2, mod);
            printf("Case %d: Public Key = %lld Private Key = %lld
    ", ++kase, K1, K2);
        }
    }

    参考链接:

    1. http://www.bubuko.com/infodetail-587732.html

    2. https://blog.csdn.net/w4149/article/details/77750279

  • 相关阅读:
    Linux Shell脚本编程实用技巧
    Transmission在Pandorabox(Openwrt)下的交叉编译
    Pandorabox下关于vsftpd匿名访问的设置
    PandoraBox下部署阿里云(aliyun)DDNS动态域名更新(shell脚本)
    win7系统封装小记
    CF R#295 (DIV.2) E. Pluses everywhere
    CF R#295 (DIV.2) D. Cubes
    CF R#295 (DIV.2) C. DNA Alignment
    winform在线操作office--dsoframerocx第三方控件
    Dapper操作
  • 原文地址:https://www.cnblogs.com/lfri/p/11726574.html
Copyright © 2011-2022 走看看