【BZOJ】1053: [HAOI2007]反素数ant
【题意】记正整数x的因数个数为g(x),当正整数x满足:g(x)>g(i)(0<i<x)时,称x为反素数,求不超过给定N的最大反素数,N<2e9。
【算法】数论,搜索
【题解】
这个问题等价于求1~N中因数最多的最小数字。
反素数有以下性质:
1.反素数的素因子一定是从2开始的连续素数。
必要性证明:对于A^p1*B^p2,A<C<B,将B更换成C后的数字A^p2*C^p1显然小于原数且因数个数相等,与反素数的定义矛盾。
2.反素数的素因子指数一定按素因子从小到大的顺序不递增。
必要性证明:对于A^p1*B^p2(p2>p1),将p1和p2交换后的数字A^p2*B^p1显然小于原数且因数个数相等,与反素数的定义矛盾。
注意:这两条性质不满足充分性!
有了这两条性质,就可以搜索素因子指数的所有情况(素因子至多12个,到31为止),找到因数最多的最小数字。
dfs(dep,p,sum,num),第dep个素因子,上一个指数为p,因数个数为sum,数字为num。
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int prime[15]={0,2,3,5,7,11,13,17,19,23,29,31,33,37,41}; int n,mx,ans; void dfs(int dep,int p,int sum,ll num){ if(sum>mx||(sum==mx&&num<ans)){ ans=num; mx=sum; } if(dep>12||num>2e9)return; ll s=prime[dep]; int x=1; while(num*s<=n){ dfs(dep+1,x,sum*(x+1),num*s); s*=prime[dep];x++; } } int main(){ scanf("%d",&n); mx=0;ans=n; dfs(1,100,1,1); printf("%d",ans); return 0; }