Pollard-Rho
Solution
用于拆解较大数的质因子。
前置知识:Miller Rabin。
涉及到的思想:
-
利用 \(\gcd(x,y)\) 来寻找 \(x\) 的因数。
-
组合随机采样的优秀命中率。
-
\(\gcd(x\cdot z,y)=\gcd(\gcd(x,y)\times \gcd(z,y),y)\),因此可以调整步长来判断当前是否找到了因数,减少 \(\gcd\) 的调用次数。
安利一篇博文,这里面讲得挺详细的,就是有些地方……可能需要你自己理解他真正的意思。
三道板子题
【模板】Pollard-Rho算法
SP4941 FACT1 - Integer Factorization (20 digits)
「数学」约数个数和
确实算是板题,毕竟这个东西就是把数字质因子拆分。
其中第三道题转化完以后就是个 前缀和 的模板。
Code
下面是封装好的,可以直接调用,返回质因数拆分的结果。
测试了 \(114514,1919810\) 这两个数的拆分。
namespace Pollard_Rho
{
inline LL les(LL x,LL y){return x>y?x-y:y-x;}
inline LL Gcd(LL x,LL y){return !y?x:Gcd(y,x%y);}
inline LL prpr(LL x,LL y,LL p){LL s=(long double)x/p*y+1e-8;s=(ULL)(x*y)-(ULL)(s*p);if(s>=p)s-=p;return s<0?s+p:s;}
inline LL ksm(LL x,LL y,LL p){LL ans=1;for(;y;y>>=1){if(y&1)ans=prpr(ans,x,p);x=prpr(x,x,p);}return ans;}
bool pri[20];
vector<int>prime;
inline void init()
{
for(int i=2;i<20;i++){if(!pri[i])prime.push_back(i);for(auto j:prime){int now=i*j;if(now>=20)break;pri[now]=true;if(i%j==0)break;}}
pri[1]=true;srand(time(0));return;
}
inline bool Miller_Rabin(LL n,int a)
{
LL t=n-1,lst;int k=0;for(;!(t&1);t>>=1)k++;lst=t=ksm(a,t,n);
for(int i=1;i<=k;i++){t=prpr(t,t,n);if(t==1&&lst!=1&&lst!=n-1)return false;lst=t;}return lst==1;
}
inline bool ifprime(LL n){if(n<20)return !pri[n];if(n%6!=1&&n%6!=5)return false;for(auto j:prime)if(!Miller_Rabin(n,j))return false;return true;}
inline LL f(LL x,int c,LL p){LL nows=prpr(x,x,p)+c;if(nows>=p)nows-=p;return nows;}
inline LL Ame(LL n)
{
LL s,t,c;s=t=0;c=rand()%(n-1)+1;
for(int ed=1;;ed<<=1)
{
LL pro=1;s=t;for(int i=1;i<=ed;i++){t=f(t,c,n),pro=prpr(pro,les(t,s),n);if(i%127==0){LL ans=Gcd(n,pro);if(ans>1)return ans;}}
LL ans=Gcd(n,pro);if(ans>1)return ans;
}
return n;
}
vector<pair<LL,int> >getpm;
inline void Gura(LL n,int cutt)
{
if(n==1)return;if(ifprime(n)){getpm.push_back(make_pair(n,cutt));return;}
LL p=n;for(;p==n;p=Ame(n));int c=0;for(;n%p==0;n/=p)c++;Gura(n,cutt);Gura(p,cutt*c);return;
}
inline vector<pair<LL,int> > work(LL n)
{
getpm.clear();Gura(n,1);sort(getpm.begin(),getpm.end());vector<pair<LL,int> >ans;ans.clear();
for(vector<pair<LL,int> >::iterator i=getpm.begin(),j;i!=getpm.end();i=j)
{
int sum=0;for(j=i;j!=getpm.end()&&j->first==i->first;j++)sum+=j->second;
ans.push_back(make_pair(i->first,sum));
}
return ans;
}
}
int main()
{
using namespace Pollard_Rho;init();
vector<pair<LL,int> >a=work(114514);for(vector<pair<LL,int> >::iterator i=a.begin();i!=a.end();i++)printf("%lld^%d ",i->first,i->second);puts("");
vector<pair<LL,int> >b=work(1919810);for(vector<pair<LL,int> >::iterator i=b.begin();i!=b.end();i++)printf("%lld^%d ",i->first,i->second);puts("");
return 0;
}
$$\texttt{Dirty Deeds Done Dirt Cheap}$$