1. 程式人生 > >Bi-shoe and Phi-shoe (歐拉函數)

Bi-shoe and Phi-shoe (歐拉函數)

cout scan 第一個 cor 歐拉 利用 -s 積性函數 color

題目描述:

技術分享圖片技術分享圖片

題目大意:一個竹竿長度為p,它的score值就是比p長度小且與且與p互質的數字總數,比如9有1,2,4,5,7,8這六個數那它的score就是6。給你T組數據,每組n個學生,每個學生都有一個幸運數字,求出要求買n個竹子每個竹子的score都要大於或等於該學生的幸運數字,每個竹竿長度就是花費,求最小花費。

首先弄清歐拉函數的定義,詳見:https://baike.baidu.com/item/%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0/1944850?fr=aladdin

函數內容 通式: 技術分享圖片 其中p1, p2……pn為x的所有質因數,x是不為0的整數。 φ(1)=1(和1互質的數(小於等於1)就是1本身)。 歐拉函數是積性函數——若m,n互質, 技術分享圖片
特殊性質:當n為質數時, 技術分享圖片 , 證明與上述類似。 若n為質數則 技術分享圖片 如: ψ(10)=10×(1-1/2)×(1-1/5)=4; ψ(30)=30×(1-1/2)×(1-1/3)×(1-1/5)=8; ψ(49)=49×(1-1/7)= 技術分享圖片 =42。

利用歐拉函數和它本身不同質因數的關系,用篩選計算出某個範圍內所有數的歐拉函數值。

/*
特性 :
1.若a為質數,phi[a]=a-1;
2.若a為質數,b mod a=0,phi[a*b]=phi[b]*a
3.若a,b互質,phi[a*b]=phi[a]*phi[b](當a為質數時,if b mod a!=0 ,phi[a*b]=phi[a]*phi[b])
*/
int m[n],phi[n],p[n],nump;
//m[i]標記i是否為素數,0為素數,1不為素數;p是存放素數的數組;nump是當前素數個數;phi[i]為歐拉函數
int make()
{
        phi[1]=1;
    for (int i=2;i<=n;i++)
    {
        if (!m[i])//i為素數
        {
            p[++nump]=i;//將i加入素數數組p中
            phi[i]=i-1;//因為i是素數,由特性得知    
        }    
        for (int j=1;j<=nump&&p[j]*i<n;j++)  //用當前已的到的素數數組p篩,篩去p[j]*i
        {
            m[p[j]*i]=1;//可以確定i*p[j]不是素數 
            if (i%p[j]==0) //看p[j]是否是i的約數,因為素數p[j],等於判斷i和p[j]是否互質 
            {
                phi[p[j]*i]=phi[i]*p[j]; //特性2
                break;
            }
            else phi[p[j]*i]=phi[i]*(p[j]-1); //互質,特性3其,p[j]-1就是phi[p[j]]   
        }
    }
}

現用另一種思路求任意一個數N,求出ψ(N),詳見轉載博客:https://blog.csdn.net/leolin_/article/details/6642096

代碼實現:

 1 #include<stdio.h>     //歐拉之實現
 2 int ef(int n)
 3 {
 4     int cnt=n;
 5     int i;
 6     for(i=2;i<=n;i++)
 7         if(n%i==0)
 8         {
 9             cnt - =cnt/i;      //   m-m/p
10             while(n%i==0
) 11 n/=i; 12 } 13 return cnt; 14 } 15 int main() 16 { 17 int n;int m; 18 int count; 19 while(scanf("%d",&m)!=EOF) 20 { 21 22 while(m--){ 23 scanf("%d",&n); 24 count=ef(n); 25 printf("%d\n",count);} 26 } 27 return 0; 28 }

看完上面的內容,我們就知道一根長度為p的竹竿它的score其實就是歐拉函數值φ(p)。又因為一個素數p的φ(p)=p-1,所以我們只需要從x+1(x是幸運數字)開始找第一個出現的素數,那就是最小花費。

代碼實現:

 1 #include<iostream>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1e7+5;
 5 
 6 bool prime[N];
 7 
 8 void is_prime(){
 9     for(int i=2;i<N;i++){
10         prime[i]=true;
11     }
12     for(int i=2;i*i<N;i++){
13         if(prime[i]){
14             for(int j=i*i;j<=N;j+=i){
15                 prime[j]=false;
16             }
17         }
18     }
19 }
20 
21 int main(){
22     is_prime();
23     int t,n;
24     cin>>t;
25     for(int i=1;i<=t;i++){
26         cin>>n;
27         ll sum=0;
28         for(int j=1;j<=n;j++){
29             int x;
30             cin>>x;
31             for(int k=x+1;;k++){
32                 if(prime[k]){
33                     sum+=k;
34                     break;
35                 }
36             }
37         }
38         cout<<"Case "<<i<<": "<<sum<<" Xukha"<<endl;
39     }
40 }

Bi-shoe and Phi-shoe (歐拉函數)