唯一分解定理

Posted sykline

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了唯一分解定理相关的知识,希望对你有一定的参考价值。

唯一分解定理:任何一个大于1的自然数N,如果N不是质数,那么N可以分解成有限个素数的乘积;例:N=(p1^a1)*(p2^a2)*(p3^a3)......其中p1<p2<p3......

在做 UVA10375 时学到了这个算法,虽然自己理解的还不透彻,先把自己的看法写下来,日后再完善;

要用唯一分解定理第一步当然是素数打表了;之前素数打表一直用笨办法,翻了N多个题解后,看到了很多好的方法。记一下以备日后回顾用。

int primes[maxn+10],vis[maxn+10];
void getprimes()
{
    memset(vis,0,sizeof(vis));
    memset(primes,0,sizeof(primes));
    for(int i=2;i<=maxn;i++)
    {
        if(vis[i] == 0)
        {
            primes[len++] = i;
            for(int j=i*i;j <= maxn;j+=i)
                vis[j] = 1;
        }
    }
}

哈?!!第一眼表示真的没看懂,again 嗯懂了一点点,解释一下:

vis数组中0表示是素数,1表示不是素数。从第一个素数开始

2:2*2,  2*2+2,2*2+2+2.......

3:  3*3,3*3+3,3*3+3+3.......

后面的都不是素数,所以把这些都筛掉,然后把碰到的vis[i]为0的i存到primes中就可以了,这样就完成了素数打表。(至于为什么从i*i开始,还需请教各位大佬)(最后是vis数组表示有哪些素数)

memset(primes,0,sizeof(primes));
int m=sqrt(maxn+0.5),len=0;
for(int i=2; i<=m; i++)
{
    if(!primes[i])
    {
        for(int j=i*i;j <= maxn;j+=i)
        {
            primes[j] = 1;
        }
    }
}
for(int i=2;i <= maxn;i++)
{
    if(!primes[i])
        primes[len++]=i;
}

个人感觉这两种方法原理是一样的,第二种就只是少开了数组。

ok,打完表接下来就是进行分解了。

void add_integer(int n,int d)
{
    for(int i=0; i<len; i++)
    {
        while(n % primes[i] == 0)
        {
            n /= primes[i];
            e[i] += d;
        }
        if(n == 1)//提前结束,节约时间
            break;
    }
}

n是我们要分解的数字,当n在分子上的时候d为1,在分母上的时候d为-1;e数组表示的是i这个数能够分解成几个primes[i]相乘存的数值是primes[i]的次方。

double ans = 1;
for(int i=0; i <10000; i++)
{
     ans *= pow(primes[i],e[i]);
}

最后把这些数在相乘就可以了。

例如:

100经过分解之后得到的是

e[i]:           2 0 2

primes[i]:  2 3 5

相乘得2*2+5*5=100.

以上是关于唯一分解定理的主要内容,如果未能解决你的问题,请参考以下文章

唯一分解定理

UVA - 11388 唯一分解定理

HDU 1452 Happy 2004(唯一分解定理)

阶乘约数——蓝桥杯python组国赛题(C++唯一分解定理)

唯一分解定理

唯一分解定理