唯一分解定理:任何一个大于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开始,还需请教各位大佬(感谢qq_16171157朋友的指教!!))(最后是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^2=100.(感谢Dawn-K指正错误!)