SP4948题解
题目传送门。
本题主要考查 Pollard-Rho 算法。
思路
题目意思就是叫你分解质因数,没有别的东西了。
对于每一个质因子,暴力算出它的指数,注意这里是顺序输出质因子,我们只用浅浅排序一下即可。
对于 Pollard-Rho 算法,这里浅谈一下,本质上是随机化,利用生日悖论来提高算法的正确率。随机选出两个数
普通判断质数太慢了,因此我们需要一个更为高效的算法 Miller_Rabin,详细可以看这篇文章 this。
有以下图:
这也就说明为什么算法名有一个
注意事项
-
本题数据需要开到
10^{29} ,需要用__int128储存。 -
不建议使用快速乘,可以使用
ll mul(ll a,ll b,ll p){return (a*b-(ll)((__float128)a/p*b)*p+p)%p;}
接下来就是简简单单的卡常操作。
贴贴代码
#include <bits/stdc++.h>
#define ll __int128
#define Auto vector<ll>::iterator
using namespace std;
const ll Maxn=610,inf=0x3f3f3f3f;
vector<ll>S;
inline ll qread(){
ll x=0;int f=1;char ch;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=0;x=(ch^48);
while((ch=getchar())>='0'&&ch<='9') x=x*10+(ch^48);
return f?x:-x;
}
inline void print(ll x){
if(x>9) print(x/10);
putchar('0'+(x%10));
}
namespace Math{
ll mul(ll a,ll b,ll p){return (a*b-(ll)((__float128)a/p*b)*p+p)%p;}
ll Abs(ll x){return x>0?x:-x;}
inline ll ksm(ll a,ll b,ll p){
a%=p;
ll res=1;
for(;b;b>>=1,a=mul(a,a,p))if(b&1)res=mul(res,a,p);
return res;
}
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
}
using namespace Math;
namespace Miller_Rabin{
inline bool mr(ll x,ll b){
ll k=x-1;
while(k){
ll cur=ksm(b,k,x);
if(cur!=1&&cur!=x-1)return false;
if((k&1)||cur==x-1)return true;
k>>=1;
}
return true;
}
inline bool Prime(ll x){
if(x<=1)return false;
if(x==2||x==61)return true;
return mr(x,2)&&mr(x,61);
}
}
using namespace Miller_Rabin;
namespace Pollard_Rho{
#define rnd() rand()
inline ll f(ll x,ll c,ll n){
return (mul(x,x,n)+c)%n;
}
inline ll PR(ll x){
ll s=0,t=0,c=rnd()%(x-1)+1,val=1;
for(int goal=1;;goal<<=1,s=t,val=1){
for(int stp=1;stp<=goal;stp++){
t=f(t,c,x);
val=mul(val,Abs(t-s),x);
if(stp%127==0){
ll d=__gcd(val,x);
if(d>1)return d;
}
}
ll d=__gcd(val,x);
if(d>1)return d;
}
}
inline void solve(ll X){
if(!(1^X)) return ;
if(Prime(X)){S.push_back(X);return ;}
ll Y=X;while(Y==X)Y=PR(X);while(!(X%Y)) X/=Y;
solve(X);solve(Y);
}
}
ll m,a,ans1=-inf,cnt;
int main(){
srand(time(0));
while(m=qread()){
S.clear();Pollard_Rho::solve(m);
sort(S.begin(),S.end());
S.resize(unique(S.begin(),S.end())-S.begin());
for(Auto it=S.begin();it!=S.end();it++){
ll t=*it;
print(t),printf("^");
int k=0;while(m%t==0) m/=t,++k;
printf("%d ",k);
}
puts(" ");
}
return 0;
}