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; }
当你意识到,每个上一秒都成为永恒。