Gym/100753 Divisions (大数分解质因数)

题目链接https://nanti.jisuanke.com/t/28395 

题意:给出一个数N(<1e18)输出因子的个数 

对于一个大整数n,我们取任意一个数x使得x是n的质因数的几率很小,但如果取两个数x1以及x2使得它们的差是n的因数的几率就提高了(我也不会证明。。。),如果取x1以及x2使得gcd(abs(x1−x2),n)>1的概率就更高了。这就是Pollard-Rho算法的主要思想。

对于满足gcd(abs(x1−x2),n)>1的x1和x2,gcd(abs(x1−x2),n)就是n的一个因数,只需要判断它是否为素数,若为素数,则是n的质因数,否则递归此过程。

其中判断素数就使用Miller-Rabin算法。

那么我们怎样不断取得x1和x2呢? 
x1在区间[1,n]中随机(rand)出来,而x2则由x2=(x1*x1%n+c)%n推算出来,其中c为任意给定值,事实证明,这样就是比较优的。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 100001;
LL mul(LL a,LL b,LL mod) {
    if(!a) return 0;
    return ((a&1)*b%mod + (mul(a>>1,b,mod)<<1)%mod)%mod;
}
LL quickPow(LL a,LL d,LL n) {
    LL ret = 1;
    while(d) {
        if(d&1) ret = mul(ret,a,n);
        d >>= 1;
        a = mul(a,a,n);
    }
    return ret;
}
bool check(LL a,LL d,LL n) {
    if(n == a) return true;
    while(~d&1) d >>= 1;
    LL t = quickPow(a,d,n);
    while(d < n-1 && t != 1 && t != n-1) {
        t = mul(t,t,n);
        d <<= 1;
    }
    return (d&1) || t == n-1;
}
bool isP(LL n) {
    if(n == 2) return true;
    if(n < 2 || 0 == (n&1)) return false;
    static int p[5] = {2,3,7,61,24251};
    for(int i = 0; i < 5; ++i)
        if(!check(p[i],n-1,n)) return false;
    return true;
}
LL gcd(LL a,LL b) {
    if(a < 0) return gcd(-a,b);//特别注意,没这个TLE
    return b?gcd(b,a%b):a;
}
LL Pollard_rho(LL n,LL c) {
    LL i = 1,k = 2,x = rand()%n,y = x;
    while(true) {
        x = (mul(x,x,n) + c)%n;
        LL d = gcd(y - x,n);
        if(d != 1 && d != n) return d;
        if(y == x) return n;
        if(++i == k) {
            y = x;
            k <<= 1;
        }
    }
}
LL Fac[maxn],tot;
void factorization(LL n) {
    if(isP(n)) {
        Fac[tot++] = n;
        return;
    }
    LL p = n;
    while(p >= n) p = Pollard_rho(p,rand()%(n-1)+1);
    factorization(p);
    factorization(n/p);
}
map<LL,LL>ump; 
int main() {
    LL x;
    srand(time(0));
    while(~scanf("%lld",&x)){
        tot = 0;
        if(x == 1) {
            puts("1");
            continue;
        }
        if(isP(x)){
            puts("2");
            continue;
        }
        factorization(x);
        ump.clear();
        for(int i = 0; i < tot; ++i)
            ump[Fac[i]]++;
        LL  ret = 1;
    	for(int i=0;i<tot;i++)
    	{
    	    ret*=ump[Fac[i]]+1;
    		ump[Fac[i]]=0;
		}
        printf("%lld\n",ret);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dllpxfire/article/details/81037933