借用了下东北师大ACM的反素数模版。
本来我是在刷线段树的,有一题碰到了反素数,所以学了一下。。有反素数的存在,使得一个x ,使得x的约数个数,在1 到 x的所有数里面,是最大的。
这里面还涉及安叔那天讲的求一个数的约数个数,用其素数因子的指数相乘即可。
这是东北师大的模版:
View Code typedef __int64 INT; INT bestNum; //约数最多的数 INT bestSum; //约数最多的数的约数个数 const int M=1000; //反素数的个数 INT n=500000;//求n以内的所有的反素数 INT rprim[M][2]; //2*3*5*7*11*13*17>n,所以只需考虑到17即可 INT prim[14]={2,3,5,7,11,13,17,19,23,29}; //当前走到num这个数,接着用第k个素数,num的约数个数为sum, //第k个素数的个数上限为limit void getNum(INT num,INT k,INT sum,INT limit) { if(num>n)return; if(sum>bestSum){ bestSum = sum; bestNum = num; }else if(sum == bestSum && num < bestNum){ //约数个数一样时,取小数 bestNum = num; } if(k>=7) return; //只需考虑到素数17,即prim[6] for(INT i=1,p=1;i<=limit;i++){ //素数k取i个 p*=prim[k];
if(p>n||p*num>n) return; //这里也要判断一下,否则老是爆掉。 getNum(num*p,k+1,sum*(i+1),i); } } INT log2(INT n){ //求大于等于log2(n)的最小整数 INT i = 0; INT p = 1; while(p<n){ p*=2; i++; } return i; } int getrprim(){//反素数的个数 int i = 0; while(n>0){ bestNum = 1; bestSum = 1; getNum(1,0,1,log2(n)); n = bestNum - 1; rprim[i][0]=bestNum; rprim[i][1]=bestSum; i++; } return i; }
ZOJ 2562的代码
#include <iostream> #include <cstdio> typedef long long ll; using namespace std; ll prime[30]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; ll antinum; ll antisum; ll antiprime[101][2]; ll maxn; ll log2(ll n) { ll i=0,p=1; while (p<n) { p*=2; i++; } return i; } void getanti(ll num,ll sum,ll k,ll limit) { if (num > maxn) return; //cout<<num<<endl; if (sum>antisum) {antisum=sum;antinum=num;} else if (sum==antisum&&num<antinum) antinum=num; if (k>15) return; for (ll i=1,p=1;i<=limit;i++) { p*=prime[k]; if (p>maxn||num*p>maxn) return; getanti(num*p,sum*(i+1),k+1,i); } } void getnum() { antinum=1; antisum=1; //cout<<maxn<<endl; getanti(1,1,0,50); } int main() { //printf("%I64d ",maxn); // ll cur=getnum(); ll t; //cout<<cur<<endl; // for (int i=cur-1;i>=0;i--) //cout<<antiprime[i][0]<<endl; while (scanf("%lld",&t)!=EOF) { maxn=t; getnum(); printf("%lld ",antinum); } return 0; }