当前位置 博文首页 > nameofcsdn的博客:Pollard‘s rho大数分解算法

    nameofcsdn的博客:Pollard‘s rho大数分解算法

    作者:[db:作者] 时间:2021-07-12 10:04

    目录

    一,问题

    二,Pollard's rho算法思路

    1,构造递推数列

    2,生成mod n的递推数列

    3,近似生日问题

    4,Pollard's rho算法思路

    5,时间复杂度

    三,OJ实战

    HDU - 1488 Flavius Josephus Reloaded


    一,问题

    给定一个很大的整数n,求出n的一个素因子

    PS:如果求不出非平凡因子,也能说明n是素数

    ?

    二,Pollard's rho算法思路

    1,构造递推数列

    构造一个一阶至少二次的递推式,如a_{k+1}=a_k^2+c

    2,生成mod n的递推数列

    随便取初始值,根据a_{k+1}\equiv a_k^2+c(mod\,n)得到一个数列,那么数列的每一项都在[0,n-1]的范围内

    显然,数列一定会陷入循环。

    如n=30,数列{0,1,2,5,26,17,20,11,2...}

    这个数列mod 5是{0,1,2,0...}

    这个数列模3是{0,1,2,2...}

    3,近似生日问题

    生成数列是比较随机的,所以我们可以把它看做生日问题

    根据https://blog.csdn.net/nameofcsdn/article/details/116141651中的计算,第一个重复出现的数的下标的期望,不超过(1+e^{-\frac{1}{2}})\sqrt k+2,其中k是可以取的数的数目

    下文用2sqrt(k)表示,不用太关注常数

    4,Pollard's rho算法思路

    如果n有非平凡因子p,那么大概率数列mod p出现周期会比mod n出现周期早,因为前者是2sqrt(p),后者是2sqrt(n)

    按照判断链表是否有环的方法,我们依次检测a_i, a_{2i}是否相等,即是否出现周期

    因为不知道p的值,所以我们用gcd(a_i-a_{2i},\, n)>1来判断进入了mod p的循环,这样,我们就找到了因子p

    如果满足gcd(a_i-a_{2i},\, n)>1的最小i就是a_i=a_{2i},即gcd(a_i-a_{2i},\, n)=n,则n有可能是素数。

    如果确定n是合数,可以多尝试一些c的值,总能找到p的,

    如果不确定n是不是素数,多尝试一些c的值之后还是找不到因子,那n可能就是素数。

    5,时间复杂度

    平均情况下的时间复杂度是sqrt(p)*tc*tn,

    其中tc表示尝试不同的c的次数,tc的期望应该非常小,感觉小于2,

    其中tn表示单次调用gcd函数的运行时间,基本上可以理解为log n

    所以,Pollard's rho算法的平均时间复杂度是O(n^{\frac{1}{4}} * log n)

    ?

    三,OJ实战

    HDU - 1488 Flavius Josephus Reloaded

    Flavius Josephus once was trapped in a cave together with his comrade soldiers surrounded by Romans. All of Josephus' fellow soldiers preferred not to surrender but to commit suicide. So they all formed a circle and agreed on a number k. Every k-th person in the circle would then commit suicide. However, Josephus had different priorities and didn't want to die just yet. According to the legend he managed to find the safe spot in the circle where he would be the last one to commit suicide. He surrendered to the Romans and became a citizen of Rome a few years later.

    It is a lesser known fact that the souls of Josephus and his comrades were all born again in modern times. Obviously Josephus and his reborn fellow soldiers wanted to avoid a similar fiasco in the future. Thus they asked a consulting company to work out a better decision scheme. The company came up with the following scheme:

    1.For the sake of tradition all soldiers should stand in a circle. This way a number between 0 and N-1 is assigned to each soldier, where N is the number of soldiers.
    2.As changing numbers in the old scheme turned out to be horribly inefficient, the number assigned to a soldier will not change throughout the game.
    3.The consulting company will provide two numbers a and b which will be used to calculate the number of the next soldier as follows: Let x be the number of the current soldier, then the number of the next soldier is the remainder of a*x^2 + b mod N.
    4.We start with the soldier with number 0 and each soldier calculates the number of the next soldier according to the formula above.
    5.As everyone deserves a second chance a soldier will commit suicide once his number is calculated for the second time.
    6.In the event that the number of a soldier is calculated for the third time the game will end and all remaining soldiers will surrender.

    You are to write a program that given the number of soldiers N and the constants a and b determines the number of survivors.

    Input

    The input file consists of several test cases. Each test case consists of a single line containing the three integers N (2 ≤ N ≤ 10^9), a and b (0 ≤ a,b < N) separated by white space. You may safely assume that the first soldier dies after no more than one million (10^6) steps. The input is terminated by a single number 0 which should not be processed.

    Output

    For each test case output a single line containing the number of soldiers that survive.

    Sample Input

    2 1 1
    5 1 1
    10 3 7
    101 9 2
    698253463 1 181945480
    1000000000 999999999 999999999
    0

    Sample Output

    0
    2
    4
    96
    698177783
    999999994

    题意:

    输入n,a,b,生成mod n的数列,初始项为0,后面每项为前一项的平方乘以a再加b

    如果有个数出现了3次,那么就停止,对于出现了2次的数,对应的士兵杀掉,问还剩多少士兵?

    分析:

    这个其实并不是Pollard‘s rho算法,但是计算过程是差不多的,只是在这个数列中搜寻的目标不同而已。

    #include<iostream>
    #include<unordered_map>
    using namespace std;
    
    
    int main()
    {
        ios::sync_with_stdio(false);
        long long n,a,b;
        unordered_map<long long,int>m;
        while(cin>>n){
            if(n==0)break;
            cin>>a>>b;
            m.clear();
            long long x=0,ans=n;
            while(true) {
                if (m[x] == 1)ans--;
                m[x]++;
                if(m[x]==3)break;
                x = (x * x % n * a + b) % n;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    

    ?

    cs
    下一篇:没有了