唯一分解定理


唯一分解定理又稱為算數基本定理,基本內容是:

每個大於1的自然數,要么本身就是質數,要么可以寫為2個或以上的質數的積,而且這些質因子按大小排列之后,寫法僅有一種方式。

用另一種方法表示就是:

對於任何一個大於1的正整數,都存在一個標准的分解式:  N=p1^a1 * p2^a2*···*pn^an;(其中一系列an為指數,pn為質數)

此定理表明:任何一個大於 1 的正整數都可以表示為素數的積。

有這樣幾個式子:

設F(n)代表n的正因子的數量,則F(n)=(a1+1)*(a2+1)*(a3+1)*······*(an+1);

設G(n)代表n的正因子的和,則G(n)=(1+p1^2+p1^3+...+p1^a1)*(1+p2^2+p2^3+...p2^a2)*....*(1+pn^1+pn^2+...+pn^an)=

 

獲得一個數正因子數量的代碼:

primel [ ]是素數表

 1 ll getfac(ll x)
 2 {
 3     ll ans=1;
 4     for(int i=1;i<=cnt&&primel[i]<=x;i++)
 5     {
 6         ll sum=0;//當前質因數的冪指數 
 7         while(x%primel[i]==0)//當是這個數的因子時 
 8         {
 9             sum++;
10             x/=primel[i];
11         }
12         ans*=(sum+1);//應用定理的結論 
13     }
14     if(x>1)//當搜索不到的時候,如果這個數最后大於一,那么這個最后結果肯定是素數,並且指數是1 
15     ans*=2;
16     return ans;
17 }

 

來看一個應用此定理的例題:

鏈接:Light OJ 1341 Aladdin and the Flying Carpet

此題的題意就是,給定一個矩形(非正方形)的面積 a,求可以分解的長*寬有多少組,且任意一條邊不能小於b,不能重復(4*3和3*4重復)。

即求一個數可以分解為多少個正因數相乘,想到唯一分解定理,用它把所有可能的因子找出后,再除以2,在把小於b的因子暴力去除。

看代碼:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn=1e6+20;
 7 int primel[maxn];
 8 bool isp[maxn];
 9 int cnt;
10 void makel()//歐拉篩打印素數表 
11 {
12     cnt=0;
13     memset(isp,true,sizeof(isp));
14     for(int i=2;i<maxn;i++)
15     {
16         if(isp[i])
17         primel[++cnt]=i;
18         for(int j=1;j<=cnt;j++)
19         {
20             if(i*primel[j]>maxn)
21             break;
22             isp[i*primel[j]]=false;
23             if(i%primel[j]==0)
24             break;
25         }
26     }
27 }
28 ll getfac(ll x)//唯一分解定理 
29 {
30     ll ans=1;
31     for(int i=1;i<=cnt&&primel[i]*primel[i]<=x;i++)
32     {
33         ll sum=0; 
34         while(x%primel[i]==0) 
35         {
36             sum++;
37             x/=primel[i];
38         }
39         ans*=(sum+1);
40     }
41     if(x>1) 
42     ans*=2;
43     return ans;
44 }
45 int main()
46 {
47     int t;
48     int cas=0;
49     ll a,b;
50     cin>>t;
51     makel();
52     while(t--)
53     {
54         scanf("%lld%lld",&a,&b);
55         if(a<b*b)//不可能分解為比b大的數相乘 
56         {
57         printf("Case %d: 0\n",++cas);
58         continue;
59         }
60         ll count=getfac(a)/2;//不能重復 
61         for(int i=1;i<b;i++)//去除小於b的因子 
62         {
63             if(a%i==0)
64             count--;
65         }
66         printf("Case %d: %lld\n",++cas,count);
67     }
68     return 0;
69 }

 

再看一個題:

這個題運用了分解質因子和的公式(原理)。

鏈接:LightOJ 1136 Sigma Function

這個題其實就是求1~n所有的數中,可分解為質因子的和為偶數的數有多少個。

這個其實就是那個和的公式(結論)。

把上面的結論搬下來,那個公式G(n)=(1+p1^2+p1^3+...+p1^a1)*(1+p2^2+p2^3+...p2^a2)*....*(1+pn^1+pn^2+...+pn^an);

就是要讓它等於偶數,分析一下,這首先是乘積式,如果要讓乘積為偶數,那么每一項就是偶數,可是這樣的話pi如果偶數那么所有pi為偶數的G(n)都是奇數(pi^ai一定為偶,再加個1),在剩下的情況中,得分很多情況,定TLE。於是想反面,求多少個G(n)為奇數,再減去。

如果要讓和為奇數,想奇*偶=偶,奇*奇=奇,偶*偶=偶,於是只要讓每一項(1+pi^ai)為奇數即可,如果p[i] = 2;,則其和一定為奇數(2的冪次和為偶+1),除了2以外,素數都是奇數,所以 (p[i]^0 + p[i]^1 +.....+ p[i]^e[i])要滿足是奇數的話e[i]一定是偶數(首先奇數任何次冪仍為奇數,奇+奇=偶兩兩組合后一定還剩一個奇數,然后偶+奇=奇),如果 n 是一個平方數,那么他的約數和一定是奇數,如果2*n是平方數,他的約數和也是奇數。

代碼如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 using namespace std;
 5 typedef long long ll;
 6 int main()
 7 {
 8     int t,cas=0;
 9     ll n;
10     cin>>t;
11     while(t--)
12     {
13         scanf("%lld",&n);
14         ll ans;
15         ans=n-(ll)sqrt(n)-(ll)sqrt(n/2);
16         printf("Case %d: %lld\n",++cas,ans);
17     }
18     return 0;
19 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM