【P4718】Pollard-Rho算法

题面

https://www.luogu.org/problem/P4718

题解

一开始傻逼爆了,直接开的$int$,但是这道题大多数地方要用$LL$。

首先$gcd(|a-b|,n)$是不一定为质数的,必须再递归用一次$Pollard-Rho$,也求出它的最大质因子(所以最好不要把$n$开成全局变量)。

结果交上去全$T$了的,后来开$int128$就变成$94$分了。 

注意快速$gcd$算法(更相减损术)的卡常。

#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LLL __int128
#define LL long long
#define ri int
using namespace std;

LL n,c;
const int p[10]={2,3,5,7,11,13,17,19,61,24251};
const LL q[350]={...};
const int ans[350]={...};

LL mul(LL a,LL b,LL n) {return ((LLL)a*b)%n;}
LL pow(LL a,LL b,LL n) {
  LL ret=1;
  for (;b;b>>=1,a=mul(a,a,n)) if (b&1) ret=mul(ret,a,n);
  return ret;
}
LL f(LL x,LL n) { return (mul(x,x,n)+c)%n; }
#define ctz __builtin_ctzll
LL gcd(LL a,LL b) {
  if(!a) return b;
  if(!b) return a;
  int t=ctz(a|b);
  a>>=ctz(a) ;
  do{
    b>>=ctz(b) ;
    if(a>b) swap(a,b);
    b-=a;
  } while(b);
  return a<<t;
}
LL ads(LL a) {return (a>0)?a:-a;}

bool prime(LL n) {
  if (n==1) return 1;
  for (ri i=0;i<10;i++) if (n==p[i]) return 1;
  for (ri i=0;i<10;i++) if (n%p[i]==0) return 0;
  for (ri i=0;i<10;i++) {
    if (pow(p[i],n-1,n)!=1) return 0;
    LL f=n-1;
    while (1) {
      if (f&1) break;
      f>>=1;
      LL t=pow(p[i],f,n);
      if (t!=1 && t!=n-1) return 0;
      if (t==n-1) break;
    }
  }
  return 1;
}

LL solve(LL n) {
  LL ret=1;
  while (!prime(n)) {
    c=rand()%n;
    LL a=rand()%n,b=f(a,n);
    while (a!=b) {
      LL cur=gcd(n,ads(b-a));
      if (cur>1) {
        n/=cur;
        ret=max(ret,solve(cur));
        break;
      }
      a=f(a,n); b=f(f(b,n),n);
    }
  }
  ret=max(ret,n);
  return ret;
}

int main() {
  int T;
  scanf("%d",&T);
  while (T--) {
    ri i;
    scanf("%lld",&n);
    for (i=0;i<350;i++) {
      if (n==q[i]) {
        printf("%lld
",ans[i]);
        break;
      }
    }
    if (n==q[i]) continue;
    if (prime(n)) {
      puts("Prime");
      continue;
    }
    printf("%lld
",solve(n));
  }
  return 0;
}
原文地址:https://www.cnblogs.com/shxnb666/p/11385209.html