HAOI2007 反素数

传送门

这道题或许是披着数论外衣的搜索题……

在进行爆搜之前,我们有几个结论性的东西需要进行证明。

1.区间内最大的反质数是因子最多的最小的数。

这个很好理解,首先它必须因子最多,其次,如果他不是最小的那一个的话,那么它的前面就会有一个因子个数与之相同的数,那他就不是反素数了。

2.本题数据范围之内,一个数不会有多于10个不同的素因子。

我们把前11个素数乘起来,已经超出了2*109,所以必然不会有多于10个不同的素因子。

3.本题数据范围之内,任何一个素因子的指数不超过31.

这个还是很好理解,毕竟int的最大值我们都懂。

4.如果一个数是反素数,那么它必然可以被唯一分解为以下形式:x = 2c1 * 3c2 * …… 29cn,满足c单调不增,p必然是前10个素数。

这个是为什么呢?首先我们先证明后一点,它必然能被分解为最小的几个连续的素数,而且素数不大于29。我们 假设一个素数p是x的一个质因子,那么x / pk * qk,(q是一个小于p的质数),这个数它的因子个数和x是相等的(这个很好证明,数的因子个数计算公式),但是它明显要比x小,说明x不是一个反素数。这样推理出来,那么x必然被分解为连续的几个最小的素数,否则的话,我们就能找到一个数,比它小而因子个数和它一样多。

其实这个也已经证明了前一点,如果指数出现了递增,我们把增的那个指数减少,前面的增加,这样又得到因子数相同而更小的一个数,他就又不是反素数了。

有了这么多的限制之后,我们直接爆搜就行。

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 20005;
const int N = 10000005;
const int INF = 2000000005;
const int mod = 13;
 
ll read()
{
   ll ans = 0,op = 1;
   char ch = getchar();
   while(ch < '0' || ch > '9')
   {
      if(ch == '-') op = -1;
      ch = getchar();
   }
   while(ch >='0' && ch <= '9')
   {
      ans *= 10;
      ans += ch - '0';
      ch = getchar();
   }
   return ans * op; 
}

ll n,p[12] = {2,3,5,7,11,13,17,19,23,29},minn = INF,mtot;

void dfs(ll sum,ll lim,ll cur,ll tot)
{
   if(cur >= 10)
   {
      if(tot > mtot || !mtot) mtot = tot,minn = sum;
      else if(tot == mtot) minn = min(minn,sum);
      return;
   }
   rep(i,0,lim)
   {
      if(sum > n) break;
      dfs(sum,i,cur + 1,tot * (i + 1));
      sum *= p[cur];
   }
}

int main()
{
   n = read();
   if(n == 1) printf("1\n");
   else dfs(1,31,0,1),printf("%lld\n",minn);
   return 0;
}

 

posted @ 2018-10-29 22:31  CaptainLi  阅读(136)  评论(0编辑  收藏  举报