唯一分解定理:任何一个大于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^2=100.