码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ1053 [HAOI2007]反素数 & BZOJ3085 反质数加强版SAPGAP

时间:2017-08-17 10:27:21      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:最大的   ons   desc   prim   max   ati   整数   dfs   反素数   

BZOJ 1053

Description

 

  对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。如果某个正整数x满足:g(x)>g(i) 0<i<x
,则称x为反质数。例如,整数1,2,4,6等都是反质数。现在给定一个数N,你能求出不超过N的最大的反质数么

Input

  一个数N(1<=N<=2,000,000,000)。

Output

  不超过N的最大的反质数。

Sample Input

1000

Sample Output

840

题解

可以发现,如果某个数是反质数,那么它的质因子一定是前$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

标签:最大的   ons   desc   prim   max   ati   整数   dfs   反素数   

原文地址:http://www.cnblogs.com/y-clever/p/7379641.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!