数论 —— 约数
【唯一分解定理】
對于任意一個大于 1 的正整數 n,都有且只有一種方式寫出其素因子的乘積表達式。
即:,其中,?均為素數
因此,當給出一個數 n 時,可以暴力枚舉,以獲取 n 的素因子
map<int, int> num;//記錄素因子個數 int factor[N],cntF;//記錄素因子 void getFactor(int n){cntF = 0;num.clear();for (int i = 2; i <= n / i;i++){if(n%i == 0)//記錄素因子factor[cntF++] = i;while(n%i == 0) {n /= i;num[i]++;//記錄素因子個數}}if(n > 1) {factor[cntF++] = n;num[n]++;} } int main(){int n;scanf("%d",&n);getFactor(n);for(int i=0;i<cntF;i++)cout<<factor[i]<<":"<<num[factor[i]]<<endl;return 0; }【約數個數函數】
對于一個整數 n,將其通過唯一分解定理分解,有:?
那么,n?的因子個數為:
顯然,d(n) 是一個積性函數,那么可以用線性篩求出
由于每個數由其最小質因子篩出,因此要開一個輔助數組 num[i] 來表示 i 最小因子的次冪
那么,可分為以下三種情況討論
1)i 是質數
當 i 為質數時,其約數僅有 1 與其自身,顯然存在:d[i]=2,num[i]=1
2)i%prime[j]!=0
當 i%prime[j]!=0 時,i 沒有 prime[j] 這個質因子,然而 i*prime[j] 中包含 prime[j]
根據前面得到的?d[i]=(a1+1)(a2+1)...(ak+1)
因此,要加上當前的?prime[j],從而有:d[i*prime[j]]=(a1+1)(a2+1)...(ak+1)(1+1)
即:d[i*prime[j]]=d[i]*d[prime[j]]=d[i]*2
由于當前的 prime[j] 必然是 i*prime[j] 的最小素因子,因此當前最小素因子的個數為:num[i*prime[j]]=1
3)i%prime[j]=0
當 i%prime[j]=0 時,i 中必然包含了至少一個 prime[j],且?prime[j] 必定是 i 的最小質因數
由于 i?prime[j] 與 i 相比,至少多了一個最小質因子,根據前面得到的?d[i]=(a1+1)(a2+1)...(ak+1)
那么有:d[i?prime[j]]=(a1+1+1)(a2+1)...(ak+1)
即:d[i?prime[j]]=d[i]/(a1+1)?(a1+2)
當前最小素因子的個數也在原來的 num[i] 的基礎多了一個,即:num[i?prime[j]]=num[i]+1
int d[N],num[N]; int prime[N],cnt; bool bprime[N]; void getFactorNum(int n){d[1]=1;num[1]=1;for(int i=2;i<=n;i++){if(!bprime[i]){prime[++cnt]=i;d[i]=2;num[i]=1;}for(int j=1;j<=cnt&&i*prime[i]<=n;j++){bprime[i*prime[j]]=true;if(i%prime[j]!=0){d[i*prime[j]]=2*d[i];num[i*prime[j]]=1;}else{d[i*prime[j]]=d[i]/(num[i]+1)*(num[i]+2);num[i*prime[j]]=num[i]+1;break;}}} } int main(){int n;scanf("%d",&n);getFactorNum(n);for(int i=1;i<=n;i++)printf("%d\n",d[i]);return 0; }【約數和函數】
對于一個整數 n,將其通過唯一分解定理分解,有:?
其所有因子之和為:
顯然,σ(n) 是一個積性函數,那么可以用線性篩求出
設 sp[i] 表示?i 的最小質因子的各次冪之和,即:
那么,可分為以下三種情況討論:
1)i?是質數時
當 i?為質數時,其約數僅有 1 與其自身,顯然存在:sd[i]=i+1,sp[i]=i+1
2)i%prime[j]!=0
當?i%prime[j]!=0 時,i 中不包含 prime[j] 這個素因子,且 prime[j] 一定是 i*prime[j] 的最小素因子
那么由:?
得:
即有:sd[i*prime[j])=sd[i]*sd[prime[j]]
相應的,sp[i*prime[j]]=sp[prime[j]]=prime[j]+1
3)i%prime[j]=0
當?i%prime[j]=0 時,i 中至少包含了一個 prime[j]
那么由:?
得:
可以發現,兩式唯一的不同在于:
那么:sd[i*prime[j]=sd[i] / (1) * (2)
即:sd[i*prime[j]=sd[i]/sp[i]*(sp[i]*prime[j]+1)
相應的,sp[i*prime[j]]=sp[i]*prime[j]+1
int prime[N],cnt; bool bprime[N]; int sd[N],sp[N]; void getSd(int n){sd[1]=1;sp[1]=1;for(int i=2;i<=n;i++){if(!bprime[i]){prime[++cnt]=i;sd[i]=i+1;sp[i]=i+1;}for(int j=1;j<=cnt&&prime[j]*i<N;j++){int temp=prime[j]*i;bprime[temp]=true;if(i%prime[j]==0){sp[temp]=sp[i]*prime[j]+1;sd[temp]=sd[i]/sp[i]*sp[temp];break;}sd[temp]=sd[i]*sd[prime[j]];sp[temp]=prime[j]+1;}} } int main(){int n;scanf("%d",&n);getSd(n);for(int i=1;i<=n;i++)printf("%d\n",d[i]); }【最高次冪】
對于一個整數 n,若要求滿足 n=a^p 這個式子最大的 p,其中 n 可能是負數,a、p 是整數
則可知:p = GCD(k1,k2,k3,...,kn)
比如:24 = 2^3*3^1,p 應該是 GCD(3, 1) = 1,即:24 = 24^1
? ? ? ? ? 324 = 3^4*2^2,p應該是 GCD(4, 2) = 2,即:324 = 18^2
int prime[N],cnt; bool bprime[N]; void make_prime(){memset(bprime,false,sizeof(bprime));for(int i=2;i<=N;i++){if(!bprime[i]){prime[cnt++]=i;for(LL j=i*2;j<=N;j+=i)bprime[j]=true;}} } int GCD(int a, int b){return a % b == 0 ? b : GCD(b, a % b); }int main(){makePrime();int n;scanf("%d",&n);bool flag=false;if(n<0){//負數的情況n=-;flag=true;}int res=0;for(int i=0;i<cnt&&prime[i]<=n;i++){if(n%prime[i]==0){//枚舉每一組的prime^kint k=0;while(n%prime[i]==0){k++;n/=prime[i];}//求p=GCD(k1,k2,...,kn)if(res==0)res=k;elseres=GCD(res,k);}}if(n>1)//若質數除不盡res=GCD(res,1);if(flag){//負數時,冪不可能為偶數while(res%2==0)res/=2;}printf("%d\n",res);return 0; }【例題】
總結
- 上一篇: 病毒侵袭持续中(HDU-3065)
- 下一篇: 统计难题(HDU-1251)