BZOJ 1053 - 反素数ant - [数论+DFS][HAOI2007]
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1053
题解:
可以证明,$1 \sim N$ 中最大的反质数,就是 $1 \sim N$ 中约数个数最多的数中,最小的那个。
证明:假设 $1 \sim N$ 中最大的反质数 $x$ 不是 $1 \sim N$ 中约数个数最多的,那么必然存在至少一个不等于 $x$ 的数字 $y$,它是 $1 \sim N$ 中约数个数最多的数中最小的,显然有 $g(y) > g(x)$。
那么,分类讨论两种情况:
1、$x < y$,显然 $[1,y)$ 中不可能找到一个 $i$ 使得 $g(y) \le g(i)$,因此 $g(y)$ 是一个反质数,且 $x < y$,$y$ 优于 $x$,不可能选 $x$ 作为答案。
2、$y > x$,此时 $g(y) > g(x)$,$x$ 不是一个反质数,不应当选择 $x$ 作为答案。
因此,不管怎么样,都不可能选择 $x$ 作为答案,因此只能选择 $1 \sim N$ 中约数个数最多的数作为答案,又显然的,应当选这些数字中最小的那一个。
证毕。
然后,我们可以进一步考虑,在给出的 $N \le 2e9$ 的前提下,$1 \sim N$ 中的任何数,其不相同质因子的个数不会超过 $10$ 个,因为 $2 \times 3 \times 5 \times 7 \times 11 \times 13 \times 17 \times 19 \times 23 \times 29 = 6469693230 > 2e9$。
同时,$1 \sim N$ 中的任何数,其任意一个质因子的幂次都不会超过 $30$,因为 $2^{31} > 2e9$。
最后,还可以证明 $x$ 如果是一个反质数,那么必然可以分解质因数成 $2^{c_1} \times 3^{c_2} \times 5^{c_3} \times 7^{c_4} \times 11^{c_5} \times 13^{c_6} \times 17^{c_7} \times 19^{c_8} \times 23^{c_9} \times 29^{c_{10}}$,且满足 $c_1 \ge c_2 \ge \cdots \ge c_{10} \ge 0$。
这个是因为,假设 $x$ 有一个质因子 $p>29$,那么 $2 \sim 29$ 这 $10$ 个质数必然至少有一个不能整除 $x$ 了,假设这个质数是 $q$,那么显然如果将 $p^k$ 换成 $q^k$,$x$ 就会变小,而且约数个数不变,也即存在一个 $x'<x$ 且 $g(x') = g(x)$,那么 $x$ 就不是反质数,证毕。
综上,我们可以暴力搜索 $2^{c_1} \times 3^{c_2} \times 5^{c_3} \times 7^{c_4} \times 11^{c_5} \times 13^{c_6} \times 17^{c_7} \times 19^{c_8} \times 23^{c_9} \times 29^{c_{10}}$ 中的 $c_1 \sim c_{10}$。我们可以通过 $c_1 \sim c_{10}$ 算出对应的约数个数,我们只需要维护约数个数最多的最小数即可。
AC代码(1A很舒服):
/************************************************************** Problem: 1053 User: Dilthey Language: C++ Result: Accepted Time:24 ms Memory:1288 kb ****************************************************************/ #include<bits/stdc++.h> #define fi first #define se second #define mk(a,b) make_pair(a,b) using namespace std; typedef long long ll; ll n; int p[10]={2,3,5,7,11,13,17,19,23,29}, c[10]; pair<ll,int> ans; void dfs(int pos,int limit,ll num,int cnt) { if(pos>=10) { if(cnt>ans.se) ans=mk(num,cnt); if(cnt==ans.se && num<ans.fi) ans=mk(num,cnt); return; } for(ll i=0,now=1;i<=limit;i++,now*=p[pos]) { if(num*now>n) break; dfs(pos+1,i,num*now,cnt*(i+1)); } } int main() { cin>>n; ans=mk((ll)(2e9+50),0); dfs(0,30,1LL,1); cout<<ans.fi<<endl; }