Miller-Rabin + poLLard-rho 模板

 详见:《算法导论》

HDU 4344

1、长度是N的因子(且大于1小于N),集合中的元素得两两互质 

2、为了尽可能多的选出,每个L的质因子应当只包含N的一个质因子,L是一个质因子的整数次,所以K的值就是N中不同质因子的个数

3、要想和最大,那么使得每个L最大,只要使得质因子的指数最大即可

所以用pollard_rho分解N的质因数,然后统计不同的质因子个数K,以及计算所有相同质因子乘积的和S

特殊情况:如果N本身是某个质数的整数i次幂,那么K只能等于1,因为L要小于N,所以L最大为该质数的i-1次幂

以前poj上用过这个模板。。。放在这道题上wa到爆了。。。最后发现是没注意上面这种情况。。。

吐嘈一下,恶心的HDOJ,不能用lld。。。。!!

 

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <map>
#include <sstream>

#define CL(arr, val)    memset(arr, (val), sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   ((l) + (r)) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)    (1 << (x))
#define iabs(x)  ((x) > 0 ? (x) : -(x))

typedef long long LL;
const double eps = 1e-8;
//const int inf = ~0u>>2;

using namespace std;

const int C = 16381;
const LL inf = 1<<22;


map<LL, LL> mp;

LL gcd(LL a, LL b) {
    return b ? gcd(b, a%b) : a;
}

LL mod_mul(LL a, LL b, LL n) {
    LL res = 0;
    while(b > 0) {
        if(b&1)    {res = (res + a); if(res >= n)   res -= n;}
        a = (a + a); if(a >= n) a -= n;
        b >>= 1;
    }
    return res;
}

LL mod_exp(LL a, LL b, LL n) {
    LL res = 1;
    while(b > 0) {
        if(b&1)    res = mod_mul(res, a, n);
        a = mod_mul(a, a, n);
        b >>= 1;
    }
    return res;
}

bool miLLer_rabin(LL n) {
    if(n == 2 || n == 3 || n == 5 || n == 7 || n == 11)    return true;
    if(n == 1 || !(n%2) || !(n%3) || !(n%5) || !(n%7) || !(n%11))    return false;

    LL x, pre, u;
    int i, j, k = 0;
    u = n - 1;

    while(!(u&1)) {
        k++; u >>= 1;
    }
    srand((LL)time(0));
    for(i = 0; i < 5; ++i) {    //5次足够AC了
        x = rand()%(n-2) + 2;
        if((x%n) == 0)    continue;
        x = mod_exp(x, u, n);
        pre = x;
        for(j = 0; j < k; ++j) {
            x = mod_mul(x, x, n);
            if(x == 1 && pre != 1 && pre != n-1)    return false;
            pre = x;
        }
        if(x != 1)    return false;
    }
    return true;
}

LL poLLard_rho(LL n, LL c) {
    LL x, y, d;
    LL i, k;
    i = 1; k = 2;

    srand((LL)time(0));
    x = rand()%(n-1) + 1;
    y = x;

    while(1) {
        i ++;
        x = (mod_exp(x, 2, n) + c) % n;
        d = gcd(y - x + n, n);
        if(d != 1 && d != n)    return d;
        if(x == y)    return n;
        if(i == k) {
            y = x; k *= 2;
        }
    }
}

void factor(LL n, LL c) {
    if(n <= 1)    return ;
    LL r, d;
    if(miLLer_rabin(n)) {
        if(mp[n] == 0)  mp[n] = n;
        else    mp[n] *= n;
        return ;
    }
    r = poLLard_rho(n, c--);
    d = n/r;
    factor(d, c);
    factor(r, c);
}

int main() {
    //freopen("data.in", "r", stdin);

    int t;
    LL n, k, sum;
    scanf("%d", &t);
    while(t--) {
        cin >> n;
        if(miLLer_rabin(n))    {cout << 1 << " " << 1 << endl;}
        else {
            sum = 0; k = 0;
            mp.clear();
            factor(n, C);
            map<LL, LL>::iterator it;

            for(it = mp.begin(); it != mp.end(); ++it) {
                k++; sum += it->second;
            }
            it = mp.begin();
            if(k == 1)  cout << k << " " << sum/it->first << endl;
            else    cout << k << " " << sum << endl;
        }
    }
    return 0;
}

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/vongang/archive/2012/08/08/2629047.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值