题解 P1463 【[POI2002][HAOI2007]反素数】
看了看好像都是打表的
我来说一说正解吧
1、分析题意
性质1: 划重点、敲黑板
1~N中的最大的反质数,就是1~N中约数个数最多的数中最小的一个 。
简证:
设m是1~N中约数个数最多的数中最小的一个。根据m的定义,m显然满足:
第一条性质:
第二条性质:
根据反素数的定义,第一条性质说明 m 是反质数,第二条性质说明大于 m 的数都不是反质数,所以 m 即为所求。
性质2: 再敲黑板
1~N中任何的不同质因子都不会超过10个,且所有质因子的指数总和不超过30。
简证:这个很好证明 qwq
最小的 11 个质数的积
2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 * 31 > 2 * 10^9
所以,N ≤ 2 10^9 不可能有多于10个不同的质因子。
即使只包含最小的质数2,仍然有 2 ^ 31 > 2 10^9 所以 N ≤ 2 * 10^9 的质因子不会超过30个。
性质3: 累了,不敲了
x为反质数的必要条件是:x分解质因数后可写作2^c1 3^c2 ...... *29 ^ c10,并且c1≥c2≥c3≥......≥c10≥0 。
通俗的讲,x的质因子是连续的若干个最小的质数,并且质数单调递增。
简证:
采用反证法。由性质2可得,若x的质因数分解式中存在一项p^k(p>29),则必定有一个不超过29的质因子p1不能整除x。根据算数基本定理的推论,x / p^k * p1^k 的约数个数与x的约数个数相等,但前者更小,这与反质数的定义矛盾。故x只包含29以内的质因子。
同理,若x的质因子不是连续的若干个最小的,或者指数不单调递减,我们也可以通过上述交换质因子的方法,得到一个比x更小、但约数个数相等的整数。因此,假设不成立,原命题成立。
综上所述,我们可以使用DFS尝试搜索前10个质数的指数,并满足指数递减、总乘积不超过N,同时记录约数的个数。
在这两个限制条件下,搜索量实际非常小,每当搜索出一个满足条件的整数的时候,我们就按照性质一的结论更新答案,最终得到约数个数最多的数中最小的一个。
按理来说应该到了撒花结尾的时刻了,但是我还是打算放上代码
#include <algorithm>
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std ;
int pri[15] = {0,2,3,5,7,11,13,17,19,23,29,31};
//最小的11个质数
ll best = -1 , num = -1 ;
//万一答案是0呢?
int n ;
void dfs(ll x , int rest , int m, int up)
//x为当前数字的大小,m为当前数字约数的个数
//rest为当前质数的编号,up为小于三十的当前指数和
{
if(m > best || (m == best && x < num))
num = x , best = m ;
//根据性质一的更新答案过程
ll ans = x ;
int i = 0 ;
while(i < up)
{
++ i ;
if(n / ans < pri[rest])
//保证总乘积不超过N
return ;
int kkk = m * (i + 1 ) ;
ans *= pri[rest] ;
if(ans <= n)
dfs(ans , rest + 1 , kkk , i) ;
//保证了质数的单调递减
}
//加上这两个搜索的剪枝,就会感到dfs快的飞起 哈哈哈
}
int main()
//及其卑微的主函数
{
scanf("%d" , &n) ;
dfs(1 , 1 , 1 , 30);
printf("%lld\n" , num);
}
看懂再抄谢谢