[Luogu 4718]【テンプレート】Pollard-Rhoアルゴリズム[pollrd-ρ][Miller-Rabbin]


Link https://www.luogu.org/problemnew/show/P4718
Miller−Rabbinは、大きな数のp p pが素数であるかどうかを迅速に検出するために使用される.
0二次検出:x 2≡1(m o d p)x^2equiv 1pmod{p}x 2≡1(modp)(p p p pは素数であり、0≦x

次に,a a a aをランダムに1回ずつランダムにし,まずフェルマa p−1≡1(m o d p)a^{p−1}equiv 1pmod{p}ap−1≡1(modp)からa p−1 2 k a^{frac{p−1}{2 k}}a 2 kp−1とa p−1 2 k−1 a^{frac{p−1}{2 k−1}}a 2 k−1とa p−1 2 k−1に基づいて2回検出する.比較的一般的な書き方は,a a aとして前⑨素数(2~23)を検出することである.(比較して)小さをすばやく判断することもできます
具体的な手順:ランダムa a、p−1 p−1 p−1の2 2 2を1個ずつ除去し、隣接する2個が二次検出を満たすか否かを判定する
Pollard-ρ 大合数N N N Nを分解する.
誕生日パラドックスの思想の核心はx 1⋯x n x_を組み合わせて選択することにある.1\cdots x_n x1​⋯xn​ ;(∣x i−x j∣,N)∈(1,N)(|x_i−x_j|,N)in(1,N)(∣xi−xj∣,N)∈(1,N)では,N N N Nの因数∣x i−x j∣|x_i-x_j| ∣xi​−xj​∣ . x i x_ixiは完全にx i−1 x_{i−1}xi−1が決定すると明らかにループする.誕生日パラドックスサイクル節の期待O(p)O(sqrt{p})O(p)に基づいて,j=2 i j=2 i=2 i,i i i iを列挙し,現在N Nがふるいにかけられていない最小素因数p pを仮定した.(最小のそれを考えるのは……型のサイクルが最小なので、先にそれを出す確率が高い)そしてy u=x u%p y_u=x_u%p yu=xu%pは一定のサイクル(たぶん?)比x u x_uxuは早いのでx i=k 1 p+y 1,x 2 i=k 2 p+y 2 x_i=k_1p+y_1,x_{2i}=k_2p+y_2 xi​=k1​p+y1​,x2i​=k2​p+y2​ . このとき(∣x i−x j∣,N)(|x_i−x_j|,N)(∣xi−xj∣,N)を求めるとp p p pが得られる.y y y yサイクル節はpsqrt{p}pが期待され、y y yは約≦Nlesqrt{N}≦Nが期待されるので、O(N 1/4)O(N^{1/4})O(N 1/4)が期待される
Pollardで-ρ では、x 1=2 x_を選択します.1=2 x 1=2、そしてx i≡x i−1 2+α x_i\equiv x_{i-1}^2+\alpha xi​≡xi−12​+α ,これでは2 2 2 2を判断できないので特判(2 2 2を判断できない証明:モジュール4 4 4の意味に気づくと発生するだけα + 1\alpha+1 α+1またはα\alpha α )
1つの最適化可能な点は、i i i当を列挙し続け、(x i−x j∣,N)=1(|x_i−x_j|,N)=1(∣xi−xj∣,N)=1が一般的にバッチgcdを用いて加速し、一般的にはN 10sqrt[10]{N}10 Nを一括gcdを求めるステップとして有効に複雑さを低減できることに留意することである(確かにそうだ.
具体的な手順:コードがはっきりしていてかわいい

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<12,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<12], *frS=frBB, *frT=frBB;
template<typename T>
inline void read(T& x)
{
    x=0;char ch=getchar();bool w=0;
    while(!isdigit(ch))w|=(ch=='-'),ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    w?(x=-x):0;
}
inline long long gcd(long long a, long long b)
{
    return !b?a:gcd(b,a%b);
}
inline void exgcd(long long a, long long b, long long& d, long long& x, long long& y)
{
    if (!b) { d = a; x = 1; y = 0; return;}
    exgcd(b, a%b, d, y, x); y -= x * (a / b);
}
inline long long ReMul(long long a, const long long b, const long long& p)
{
    static long long t;
    t = (long double) a * b / p;
    return ((a * b - t * p) % p + p) % p;
}
inline long long qpowm(long long a, long long b, const long long& p)
{
    if (b <= 0) return 1;
    long long ret = 1;
    while (b)
    {
        if (b & 1) ret = ReMul(ret, a, p);
        a = ReMul(a, a, p);
        b >>= 1;
    }
    return ret;
}
long long Prime[9] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
long long PowList[80];
inline bool Miller(const long long& x)
{
    long long tem;
    for (register int i = 0; i < 9; ++i)
    {
        if (Prime[i] == x) return true; // == 2, 3, 5, 7, 11, 13, 17, 19, 23
        if (Prime[i] > x) return false; // != 2, 3, 5, 7, 11, 13, 17, 19, 23
        tem = x - 1;
        PowList[0] = 0;
        while (tem % 2 == 0) ++PowList[0], tem /= 2;
        PowList[++PowList[0]] = qpowm(Prime[i], tem, x);
        for (register int j = PowList[0] - 1; j >= 1; --j)
        {
            PowList[j] = ReMul(PowList[j+1], PowList[j+1], x);
        }
        for (register int j = 1; j <= PowList[0]; ++j)
        {
            if (PowList[j] == x - 1) break;
            if (PowList[j] != 1) return false;
        }
    }
    return true;
}
#define SeMul(a, b) a = ReMul(a, a, b)
inline long long IdAbs(const long long& x)
{
    return (x<0)?(-x):x;
}
inline long long Pollard_Find(const long long& N, const int& Step, const int& Alpha)
{
    if (!(N&1)) return 2;
    register long long LastX, LastY, x = 2, y = 2, Prod;
    while (true)
    {
        LastX = x, LastY = y, Prod = 1;
        for (register int i = 1; i <= Step; ++i)
        {
            SeMul(x, N), x += Alpha; (x>=N)?(x-=N):0;
            SeMul(y, N), y += Alpha; (y>=N)?(y-=N):0;
            SeMul(y, N), y += Alpha; (y>=N)?(y-=N):0;
            Prod = ReMul(Prod, IdAbs(x - y), N);
        }
        Prod = gcd(N, Prod);
        if (Prod == 1) continue;
        if (Prod != N) return Prod; // Prod(Before GCD) == 0
        x = LastX, y = LastY;
        for (register int i = 1; i <= Step; ++i)
        {
            SeMul(x, N), x += Alpha; (x>=N)?(x-=N):0;
            SeMul(y, N), y += Alpha; (y>=N)?(y-=N):0;
            SeMul(y, N), y += Alpha; (y>=N)?(y-=N):0;
            Prod = gcd(N, IdAbs(x - y));
            if (Prod == 1) continue;
            if (Prod == N) return 0;
            return Prod;
        }
        
        //WHY
        exit(1);
    }
}
inline long long Pollard_Init(const long long& N)
{
    if (Miller(N)) return N;
    int Step = pow(N, 0.1), Alpha = 1; long long P = 0;
    while (!P) P = Pollard_Find(N, Step, Alpha), ++Alpha;
    return max(Pollard_Init(P), Pollard_Init(N/P));
}
int main()
{
    int T;
    long long n, p;
    read(T);
    while(T--)
    {
        read(n);
        p = Pollard_Init(n);
        if (p == n) puts("Prime");
        else printf("%lld
"
, p); } return 0; }