BZOJ 2818 Gcd

       本題考查的知識點主要就是用線性篩法求歐拉函數φ,首先說一下什麼是歐拉函數:對正整數n,歐拉函數是少於或等於n的數中與n互質的數的數目。之因此要用線性篩法,是由於它能使咱們O(n)的求出值。ios

       先簡要介紹一下線性篩法求歐拉函數φ:(摘自baidu)函數

int m[maxn],phi[maxn],p[maxn],pt;//m[i]是i的最小素因數,p是素數,pt是素數個數
 
int make()
{
    int k,N=maxn;
    
    phi[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!m[i])//i是素數
        {
            p[pt++]=m[i]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<pt&&(k=p[j]*i)<N;j++)
        {
            m[k]=p[j];
            if(m[i]==p[j])//爲了保證之後的數不被再篩,要break
            {
                phi[k]=phi[i]*p[j];
/*這裏的phi[k]與phi[i]後面的∏(p[i]-1)/p[i]都同樣(m[i]==p[j])只差一個p[j],就能夠保證∏(p[i]-1)/p[i]前面也同樣了*/
                break;    
            }
            else
            {
                phi[k]=phi[i]*(p[j]-1);//積性函數性質,f(i*k)=f(i)*f(k)
            }
        }
    }
}

       以後就好作多了求出φ的前綴和乘2再減1,就行了,減得是(1,1)多算的。spa

這道題的代碼以下:code

#include<cstdio>
#include<cstdlib> 
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
 
using namespace std;
 
typedef long long ll;
const ll maxn=10000005;
 
ll i_number,m;
ll f[maxn],b[maxn],p[maxn];
   
int main()
{
    cin>>i_number;
    f[1]=1;
    for(ll i=2;i<=i_number;i++)
    {
        if(!b[i])
        {
            p[m++]=i;
            f[i]=i-1;
        }
         
        for(ll j=0;j<m&&p[j]*i<=i_number;j++)
        {
            f[p[j]*i]=f[i]*p[j];
            b[p[j]*i]=1;
            if(!(i%p[j])) break;
            f[p[j]*i]=(p[j]-1)*f[i];
        }
    }
    
    ll i_temp=0;
    
    for(ll i=1;i<=i_number;i++)
    {
        f[i]=f[i]+f[i-1];
    }  
    for(ll i=1;i<=i_number;i++)
    {
        f[i]=f[i]*2-1;
    }  
    for(ll i=0;i<m;i++)
    {
        i_temp=i_temp+f[i_number/p[i]];
    }  
    
   cout<<i_temp<<endl;
    
   return 0;
}
感謝各位觀看個人博客,但願對您有所幫助,謝謝。
相關文章
相關標籤/搜索