起源
我在做某题时,想到一个问题,在(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_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 << "};
";
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 << "};
";
else cout << ",
";
}
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 << "};
";
else cout << ",
";
}
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("
");
*/
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("
");
return 0;
}