BZOJ1053(数学结论进行剪枝搜索)

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
 
这道题博主们都直觉证明法搞得我这种蒟蒻怀疑自己的正确性了好吧……我们一起来证一证。
 
 一是尽可能取约数数目大的,然后如果数量相同只能取最小的那个才算保证了反质数,这个地方不多说;
 
二是不同的质因子(2,3,5,……)不会超过10个,因为2*3*5*……*29*31爆int了,而29是第10个。
 
三是反质数的因子一定是2、3、5、……、23、29里面选的,不会存在31以后的。原因:选了31及以上的,就注定有0~29的要选不上(根据第二条)。那么举例来说,如果是选了31而没选2,那这个数除掉31再乘上2^4显然可以得到更多约数吧;如果是选了31而没选29,那这个数除掉31再乘29,约数个数没变,数却变小了,显然刚才那个31的不是反质数(根据定义)。为什么29、23这种的就没问题而31就不可以呢?因为选29和选2不冲突啊~
 
四是把数唯一分解成2^c1 * 3^c2 * 5^c3 * …… * 29^c10的话,c1 >= c2 >= c3 >=……>=c10。原因:我们知道约数总个数用乘法原理组合计算一下为(c1+1)*(c2+1)*……(c10+1),这个+1证明时用不上啦,那就di = ci + 1吧,即d3 = c3+1。约数数量就是d1*d2*d3*……*d10了。不失一般性地我们在这里举例描述吧,假设d3 > d1,那么如果存在一个正整数x <= d3,使得(d1+x)*(d3-x)>=d1*d3,则当前这个数不是反质数。上式的意义是:如果先除掉5的x次幂再乘上2的x次幂以后约数变大了或者约数相等(但是数却变小了对吧),则违反反质数定义。然后不等式解一下得x <= c3-c1。结论已经很明显了不再解释。
 
搜索部分不说了,主要是弥补一下其他博客证明的部分。
PS:反质数有性质4,不代表有性质4的都是反质数。搜索的过程中自然会搜到真的反质数和假的反质数,但真金不怕火炼,他们都会被最后的最大反质数更新掉。
 
 1 #include <cstdio>
 2 #define ll long long
 3 #define R(x) scanf("%d", &x)
 4 #define W(x) printf("%d\n", x)
 5 #define rep(i, a, b) for (int i = a; i <= b; i++)
 6 
 7 int n, ans, CNT;
 8 int primes[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
 9 
10 void dfs(int i, int num, int cnt, int last) {
11     if (i == 10) {
12         if (cnt > CNT || (cnt == CNT && ans > num))
13             ans = num, CNT = cnt;
14         return;
15     }
16 
17     ll t = 1;
18     rep(j, 0, last) {
19         if (num * t > n)    break;
20 
21         dfs(i + 1, num * t, cnt * (j+1), j);
22         t *= primes[i];
23     }
24 }
25 
26 int main() {
27     R(n);
28     dfs(0, 1, 1, 31);
29     W(ans);
30 }
posted @ 2019-01-04 09:40  AlphaWA  阅读(369)  评论(0编辑  收藏  举报