反素数

来源:互联网 发布:mac安装农行安全控件 编辑:程序博客网 时间:2024/04/30 20:41

参见百度百科:http://baike.baidu.com/link?url=6CBrDsXMVeF3zmNwL_ugd-OEeVuVyxRFJVRnt59BJxSPiLVAzc7dEqvlxhl4topCBRE5FjeRoO-JNO3HRLU1Da

其中反素数有两个重要的性质:

<1>性质一:反素数的素因子分解中素因子必须保证是从小到大连续的.  PS:因为如果不连续我们总能构造一个比其小的数,而且该数的约数的个数和其相同

<2>性质二:反素数的素因子分解中素因子的指数是单调不增的. PS: a = p1^a1*p2^a2*p3^a3...pk^ak 假设ak-1<ak,我们完全构造得到另一个数b = a / (pk^ak*pk-1^ak-1)*(pk-1^ak*pk^ak-1)这样一来有约数个数的计算公式可得a和b的约数个数是相同的,但是b<a,因此性质二是满足的.

可以依据上述的两条性质对搜索的过程进行相应的剪枝:


#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;const int MAXM = 1010;   //反素数的个数const int MAXN = 500010; //求解该范围内的反素数ll bestNum;              //约数最多的数ll bestSum;              //约数最多的约数的个数ll rprime[MAXM][2];      //2*3*5*7*11*13*17>MAXNll prime[14] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};//当前走到num这个数,接着用第k个素数,num的约数个数为sum,//第k个素数的个数上限为limitvoid getNum(ll num, ll k, ll sum, ll limit){    if(num > MAXN) return ;    if(sum > bestSum)    {        bestSum = sum;        bestNum = num;    }    else if(sum == bestSum && num < bestNum)  //约数个数相同时,我们取较小的数    {        bestNum = num;    }    if(k >= 7) return ;    for(ll i = 1, p = 1; i <= limit; ++i)    {        p *= prime[k];        getNum(num * p, k + 1, sum * (i + 1), i);    }    return ;}//求大于等于log2(n)的最小的整数ll log2(ll n){    ll i = 0;    ll p = 1;    while(p < n)    {        p *= 2;        i++;    }    return i;}//反素数的个数int getrprime(int n){    int i = 0;    while(n > 0)    {        bestNum = 1;        bestSum = 1;        getNum(1, 0, 1, log2(n));        n = bestNum - 1;        rprime[i][0] = bestNum;        rprime[i][1] = bestSum;        i++;    }    return i;}int main(){    freopen("aa.in", "r", stdin);    return 0;}

PS:以上代码来自东北师范大学ACM集训队

原创粉丝点击