日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

NYOJ 998

發(fā)布時(shí)間:2024/4/15 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NYOJ 998 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這道題是歐拉函數(shù)的使用,這里簡(jiǎn)要介紹下歐拉函數(shù)。

  歐拉函數(shù)定義為:對(duì)于正整數(shù)n,歐拉函數(shù)是指不超過(guò)n且與n互質(zhì)的正整數(shù)的個(gè)數(shù)。

  歐拉函數(shù)的性質(zhì):1.設(shè)n = p1a1p2a2p3a3p4a4...pkak為正整數(shù)n的素?cái)?shù)冪分解,那么φ(n) = n·(1-1/p1)·(1-1/p2)·(1-1/p3)···(1-1/pk)

          2.如果n是質(zhì)數(shù),則φ(n) = n-1; ?反之,如果p是一個(gè)正整數(shù)且滿足φ(p)=p-1,那么p是素?cái)?shù)。

          3.設(shè)n是一個(gè)大于2 的正整數(shù),則φ(n)是偶數(shù)

          4.當(dāng)n為奇數(shù)時(shí),有φ(2n)=φ(n)

          5.設(shè)m和n是互質(zhì)的正整數(shù),那么φ(mn)=φ(m)φ(n)

(1)可以根據(jù)性質(zhì)1,寫出計(jì)算歐拉函數(shù)值的程序: ?復(fù)雜度為O(√n)

1 //直接求解歐拉函數(shù) 2 int euler(int n){ //返回euler(n) 3 int res=n; 4 for(int i=2;i*i<=n;i++){ 5 if(n%i==0){ 6 res=res/i*(i-1);//先進(jìn)行除法是為了防止中間數(shù)據(jù)的溢出 7 while(n%i==0) n/=i; 8 } 9 } 10 if(n>1) res=res/n*(n-1); 11 return res; 12 }

?

(2)上面這種寫法中,在for循環(huán)中選擇i時(shí),是順序選擇的。事實(shí)上性質(zhì)1 中的p1、p2、p3、p4、...pk都是質(zhì)數(shù)。如果在選擇時(shí),直接選擇質(zhì)數(shù)進(jìn)行判斷,那結(jié)果會(huì)優(yōu)化很多。

可以先把50000以內(nèi)的素?cái)?shù)用篩法選出來(lái)并保存,以方便歐拉函數(shù)使用。這樣,在不考慮篩法的時(shí)間復(fù)雜度,而單看歐拉函數(shù),其復(fù)雜度變?yōu)镺(x),x為√n以內(nèi)素?cái)?shù)的個(gè)數(shù)。

?

1 #include <cstring> 2 bool boo[50000];int p[20000]; 3 4 void prim(){ 5 //線性篩素?cái)?shù) 6 memset(boo,0,sizeof(boo)); 7 boo[0]=boo[1]=1; 8 int k=0; 9 for(int i=2;i<50000;i++){ 10 if(!boo[i]) p[k++]=i; 11 for(int j=0;j<k&&i*p[j]<50000;j++){ 12 boo[i*p[j]] = 1; 13 count++; 14 if(!(i%p[j])) break; 15 } 16 } 17 18 } 19 20 int phi(int n){ 21 int rea = n; 22 for(int i=0;p[i]*p[i]<=n;i++ ){ //對(duì)一些不是素?cái)?shù)的可不用遍歷 23 if(n%p[i]==0){ 24 rea = rea-rea/p[i]; 25 while(n%p[i]==0) n/=p[i]; 26 } 27 } 28 if(n>1) rea-=rea/n; 29 return rea; 30 }

?

(3)遞推求歐拉函數(shù)

    如果頻繁的要使用歐拉函數(shù)值,就需要預(yù)先打表。復(fù)雜度約為O(nlnn)

1 //遞推法打歐拉函數(shù)表 2 #define Max 1000001 3 int phi[Max]; 4 void Init(){ 5 for(int i=1;i<=Max;i++) phi[i]=i; 6 for(int i=2;i<=Max;i+=2) phi[i]/=2; 7 for(int i=3;i<=Max;i+=2) 8 if(phi[i]==i) 9 for(int j=i;j<=Max;j+=i) 10 phi[j]=phi[j]/i*(i-1);//先進(jìn)行除法是為了防止中間數(shù)據(jù)的溢出 11 }

?

?

應(yīng)用:NYOJ 998 ??http://acm.nyist.net/JudgeOnline/problem.php?pid=998

這道題的精華如何將符合條件的gcd(x,n)表達(dá)出來(lái):見(jiàn)代碼? d*Euler(n/d) ?中為什么乘以d的解釋 ?。?

然后是遍歷一遍小于n的數(shù),測(cè)試每個(gè)符合的數(shù)加起來(lái)即可。其實(shí)還可以更快,觀察發(fā)現(xiàn),在能夠整除n的i里面,相對(duì)應(yīng)的n/i也有相似的性質(zhì),這樣以來(lái)只需要遍歷到sqrt(n)即可。

網(wǎng)絡(luò)摘抄代碼如下:

1 2 #include<iostream> 3 #include<cstdio> 4 using namespace std; 5 6 typedef long long LL; 7 LL Euler(LL n){ 8 LL ans = n; 9 for(int i = 2; i * i <= n; i++){ 10 if(n % i == 0){ 11 ans = ans / i * (i-1); 12 while(n % i == 0) 13 n /= i; 14 } 15 } 16 if(n > 1) ans = ans / n * (n-1); 17 return ans; 18 } 19 20 int main(){ 21 LL n,m; 22 while(cin>>n>>m){ 23 LL ans = 0; 24 for(int i = 1; i * i <= n; i++){ 25 if(n % i == 0){ 26 if(i >= m){ 27 int d = i; 28 ans += d*Euler(n/d); 29 // 考慮 gcd(x,n) 1=<x<=n 30 //這個(gè)的由來(lái)是 gcd(x/d,n/d) = 1.如果我們?nèi)∫粋€(gè)能讓n/d取整數(shù)的d的取值,于是我們 31 //取到了n%i==0的i,于是 能夠滿足gcd(x,n) = d 的x的個(gè)數(shù)為Euler(n/d)個(gè) 32 //那么在該gcd = d 的情況下需要加到ans里面的d的個(gè)數(shù)就是Euler(n/d)個(gè) ,所以有ans+=d*Euler(n/d) 33 34 } 35 if(i * i != n && n / i >= m){ 36 int d = n / i; 37 ans += d*Euler(n/d); 38 } 39 } 40 } 41 cout<<ans<<endl; 42 } 43 return 0; 44 } 45

?

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/liugl7/p/6246442.html

總結(jié)

以上是生活随笔為你收集整理的NYOJ 998的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。