反素数(高合成数?)

起源

我在做某题时,想到一个问题,在\(1\)\(100000\)中,哪个数拥有最多的因子?
在uoj的群问了一下,感谢vfleaking给了我一个完美答案

传送门

前一千个反素数
一道求反素数的题,让我来贴个代码,不过写得有点丑,用的是这位大牛的搜索+剪枝方法Orz。

为了防止百度空间挂掉,这里简单复述一下:

\(p_i\)为第\(i\)个素数,比如\(p_1=2,p_2=3,p_3=5\)
\(q_i\)为第\(i\)个素数的指数。

因子个数为\((q_1+1)(q_2+1)(q_3+1) ...\)

剪枝一

\[q_1 \geq q_2 \geq q_3 \geq ...\]
证明:
假如有\(q_i < q_{i+1}\),那么令\(q_i\)加一,\(q_{i+1}\)减一,答案更优。

剪枝二

对于\(q_i(i>1)\),令\(K\)为使\(2^K>p_i\)的最小整数。
有$2^{q_1}{p_i}^{q_i} > 2^{q_1 + K - 1} {p_i}^{q_i-1} \(, 如果\)q_i\(比\)q_i-1\(优,那么\)(q_1+1)(q_i+1)>(q_1+K)q_i\(, 即\)q_i < \frac {q_1+1} {K-1}\(。这样我们就找到了\)q_i$的上界。

剪枝三

对于\(q_i(i>1)\),令\(K\)为使\(2^K>p_i\)的最小整数。
有$2^{q_1} {p_i}^{q_i} > 2^{q_1 - K}{p_i}^{q_i+1} \(, 如果\)q_i\(比\)q_i+1\(优,那么\)(q_1+1)(q_i+1)>(q_1-K+1)(q_i+2)\(, 即\)q_i > \frac {q_1-2K+1} {K}\(。这样我们就找到了\)q_i$的下界。

剪枝四

\(K\)为满足\(2^K > p_m\)的最小整数,其中\(p_m\)\(q_m\)一定为\(0\)的最小数。
\(2^{q_1}>2^{q_1-K}p_m\)
前者必然比后者优,所以\(q_1+1>2(q_1-K+1)\),即\(q_1<2K\),这样,我们得到了\(q_1\)的上界。

打表代码:

#include <cstdio>
#include <math.h>
#include <iostream>
#include <cstring>
using namespace std;

const int MAXDIGHT = 100;
#include "GNum.h" //高精度的库,这里不贴了

int main() {
    static int fac[1000000], a[1000000];
    int cnt = 0;
    memset(fac, -1, sizeof(fac));

    static GNum x;
    x.A[0] = 1;
    cout << "const prime[54] = {";

    for (int i = 2; i <100000; i ++) {
        if (fac[i] == -1) {
            cout << i;
            a[cnt ++] = i;
            fac[i] = i;
            x.mul(i);
            if (x.len > 25) break;
            cout << ',';
        }
        for (int j = 0; j < cnt && a[j] <= fac[i]; j ++) {
            fac[i * a[j]] = a[j];
        }
    }
    cout << "};\n";

    cout << "const limitUpper[16][" << cnt << "] = {";
    for (int q1 = 0; q1 < 16; q1 ++) {
        if (q1) for (int i = 0; i < 28; i ++) cout << ' ';
        cout << "{";
        for (int i = 0; i < cnt; i ++) {
            int p = a[i];
            int k = ceil(log(p) / log(2));
            int ans = ceil((double) (q1 + 1) / (k -1)) ;
            if (i == 0) cout << 16;
            else {
                if (q1 && i) cout << ans;
                else cout << "0";
            }
            if (i == cnt-1) cout << "}";
            else cout << ',';
        }
        if (q1 == 16-1) cout << "};\n";
        else cout << ",\n";
    }

    cout << "const limitLower[16][" << cnt << "] = {";
    for (int q1 = 0; q1 < 16; q1 ++) {
        if (q1) for (int i = 0; i < 28; i ++) cout << ' ';
        cout << "{";
        for (int i = 0; i < cnt; i ++) {
            int p = a[i];
            int k = ceil(log(p) / log(2));
            int ans = ceil((double) (q1 + 1 - 2* k) / k) ;
            if ((q1 && i) && ans > 0) cout << ans;
            else cout << "0";
            if (i == cnt-1) cout << "}";
            else cout << ',';
        }
        if (q1 == 16-1) cout << "};\n";
        else cout << ",\n";
    }


    return 0;
}

提交代码:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int DIG = 10000;
const int MAXDIGHT = 29;

const int prime[54] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251};
const int limitUpper[16][54] = {{16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {16,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {16,3,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {16,4,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {16,5,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {16,6,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {16,7,4,4,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    {16,8,4,4,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},
    {16,9,5,5,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},
    {16,10,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},
    {16,11,6,6,4,4,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},
    {16,12,6,6,4,4,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},
    {16,13,7,7,5,5,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},
    {16,14,7,7,5,5,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},
    {16,15,8,8,5,5,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3},
    {16,16,8,8,6,6,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3}};
const int limitLower[16][54] = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,3,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,3,2,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,4,2,2,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,4,2,2,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,5,3,3,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,5,3,3,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,6,3,3,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    {0,6,4,4,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};

struct GNum{
    int A[MAXDIGHT], len;

    GNum() {
        len = 1;
        A[0] = 0;
    }

    void input() {
        static int buf[1000];
        len = 0;
        int* ch = buf; 
        *(ch ++) = '#';
        do *ch = getchar(); while (*ch < '0' || *ch > '9');
        do *(++ ch) = getchar(); while (*ch >= '0' && *ch <= '9');
        ch --;

        int cnt = 0, num = 0, s = 1;
        while (*ch != '#') {
            num += s * (*ch - 48);
            cnt ++;
            s *= 10;
            if (cnt == 4) {
                cnt = 0;
                A[len ++] = num;
                num = 0, s = 1;
            }
            ch --;
        }
        if (cnt) A[len ++] = num;
    }

    void output() {
        printf("%d", A[len - 1]);
        for (int i = len - 2; i >= 0; i --)
            printf("%04d", A[i]);
    }

    void mul(const int &x) {
        if (x == 0) {
            len = 1;
            A[0] = 0;
            return;
        }
        for (int i = 0; i < len; i ++) {
            A[i] *= x;
        }
        for (int i = 0; i + 1 < len; i ++) {
            A[i + 1] += A[i] / DIG;
            A[i] %= DIG;
        }
        while (A[len - 1] >= DIG) {
            A[len] = A[len - 1] / DIG;
            A[len - 1] %= DIG;
            len ++;
        }
    }
};

GNum upper;

bool check(GNum &a, GNum &upper) {
    if (a.len != upper.len) return a.len < upper.len;
    for (int i = a.len - 1; i >= 0; i --) {
        if (a.A[i] != upper.A[i]) return a.A[i] < upper.A[i];
    }
    return true;
}

long long ans;
GNum num[54], ansNum;

void copyNum(GNum &des, GNum &src) {
    des.len = src.len;
    for (int i = 0; i < src.len; i ++) 
        des.A[i] = src.A[i];
}

void dfs(int depth, long long comb, int used, int p1) {
    GNum &x = num[depth];
    if (check(x, upper))
        if (comb > ans || (comb == ans && check(x, ansNum))) ans = comb, copyNum(ansNum, x);
        else;
    else return;
    GNum &y = num[depth + 1];
    copyNum(y, x);
    if (! used) return;

    int L = limitLower[p1][depth];
    int R = min(used + 1, limitUpper[p1][depth]);
    for (int i = 0; i < L; i ++) y.mul(prime[depth]);

    for (int i = L; i < R; i ++) {
        dfs(depth + 1, comb * (i + 1), i, p1);
        y.mul(prime[depth]);
    }
}

int main() {
    upper.input();
    /*
    upper.output();
    printf("\n");
    */
    num[1].A[0] = 1;
    for (int i = 0; i < 16; i ++) {
        dfs(1, i + 1, i, i);
        num[1].mul(2);
    }
    ansNum.output();
    printf("\n");
    return 0;
}

转载于:https://www.cnblogs.com/wangck/p/4298919.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值