BZOJ1053 [HAOI2007]反素数 & BZOJ3085 反质数加强版SAPGAP
Posted _rqy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1053 [HAOI2007]反素数 & BZOJ3085 反质数加强版SAPGAP相关的知识,希望对你有一定的参考价值。
BZOJ 1053
Description
Input
一个数N(1<=N<=2,000,000,000)。
Output
不超过N的最大的反质数。
Sample Input
Sample Output
题解
可以发现,如果某个数是反质数,那么它的质因子一定是前$k$个质数,且这些质数的指数$q_i$是不增的(否则我可以交换两个质数的质数的指数,在因数个数不变的前提下把答案变小),于是直接爆搜。
代码:
#include <cstdio> typedef long long LL; int n; int ans; int divnum; const int prime[20] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71 }; void dfs(int x, int y, int la, int d) { if (d > divnum || d == divnum && ans > y) { ans = y; divnum = d; } if (x >= 20) return; for (int i = 0; i <= la && y <= n; ++i, y *= prime[x]) dfs(x + 1, y, i, d * (i + 1)); } int main() { scanf("%d", &n); divnum = 0; dfs(0, 1, 10000, 1); printf("%d\n", ans); return 0; }
程序中取前20个质数是因为它们乘起来已经超过2000000000了。
BZOJ 3085
同上题,但$N\leq10^{100}$。
我们考虑,若m个质因子为$p_0, \ldots, p_{m-1}$, 指数为$q_0, \ldots, q_{m-1}$,那么对于每个质数$p_i$,我们找出最小的$k_i$使$2^{k_i} > p_i$,就有
$2^{k_i - 1} < p_i$,从而$2^{p_0 + k_i - 1}p_i^{q_i - 1} < 2^{p_0}p_i^{q_i}$。
那么既然它是反素数,我们把$2^{p_0}p_i^{q_i}$换成$2^{p_0 + k_i - 1}p_i^{q_i - 1}$质因数个数一定要减少,即$(p_0 + k_i)q_i < (p_0 + 1)(q_i + 1)$,解得
$$p_i < \frac{p_0 + 1}{k_i - 1}$$
这样就对于所有$p_i (i > 0)$给出了约束。
我们考虑一定不会出现在答案里的$p_m$,对于每个$p_i$,我们找到最小的$t_i$使$p_i^{t_i} > p_m$,那么$p_i^{q_i} > p_i^{q_i - t_i}p_m$,就一定有
$q_i+1 > 2(q_i - t_i + 1)$,即$q_i < 2t_i - 1$。
$q_m$取第一个使$q_0q_1q_2q_3\ldots q_m > n$的质数即可。
然后高精,爆搜。
代码:
#include <algorithm> #include <cctype> #include <cstdio> #include <cstring> #define reg register typedef long long LL; struct Int{ static const int w = 10000; int a[30]; Int() {} Int& operator=(const Int &x) { memcpy(a, x.a, sizeof a); return *this; } Int(int x) { memset(a, 0, sizeof a); a[0] = x; } Int& operator*=(int x) { for (reg int i = 0, t = 0; i < 30; ++i) { t = (a[i] = a[i] * x + t) / w; a[i] %= w; } return *this; } Int& operator+=(int x) { for (reg int i = 0; i < 30 && x; ++i) { x = (a[i] += x) / w; a[i] %= w; } return *this; } Int operator*(int x) { Int tmp(*this); tmp *= x; return tmp; } bool operator<(const Int &y)const{ for (reg int i = 29; ~i; --i) if (a[i] != y.a[i]) return a[i] < y.a[i]; return 0; } bool operator==(const Int &y)const{ for (reg int i = 29; ~i; --i) if (a[i] != y.a[i]) return 0; return 1; } bool operator<=(const Int &y)const{ return !(y < *this); } }; Int n; Int ans; LL divnum; const int prime[] = { 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, 257 }; const int K[] = { 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, }; int t[55]; int q[55]; int m; void dfs(int x, Int y, LL d) { if (d > divnum || (d == divnum && y < ans)) { ans = y; divnum = d; } if (x >= 55) return; int Max = 2 * (t[x] - 1); if (x) Max = std::min(Max, std::min(q[x - 1], (q[0] + 1) / (K[x] - 1))); LL t; y *= prime[x]; for (q[x] = 1; q[x] <= Max && y <= n; ++q[x], y *= prime[x]) dfs(x + 1, y, d * (q[x] + 1)); } void readInt(Int &x) { x = 0; char c; while (!isdigit(c = getchar())); do (x *= 10) += c - ‘0‘; while (isdigit(c = getchar())); } void putInt(const Int &x) { int t = 30; while (!x.a[--t]); printf("%d", x.a[t]); while (t--) printf("%04d", x.a[t]); } int main() { readInt(n); divnum = 0; Int c(1); for (m = 0; c <= n; ++m) c *= prime[m]; for (int i = 0; i < m; ++i) { t[i] = 0; for (int j = 1; j <= prime[m]; j *= prime[i], ++t[i]); } dfs(0, 1, 1); putInt(ans); return 0; }
以上是关于BZOJ1053 [HAOI2007]反素数 & BZOJ3085 反质数加强版SAPGAP的主要内容,如果未能解决你的问题,请参考以下文章