【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\n",ans[i]); break; } } if (n==q[i]) continue; if (prime(n)) { puts("Prime"); continue; } printf("%lld\n",solve(n)); } return 0; }