BZOJ 2818 Gcd

       本题考查的知识点主要就是用线性筛法求欧拉函数φ,首先说一下什么是欧拉函数:对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目。之所以要用线性筛法,是因为它能使我们O(n)的求出值。

       先简要介绍一下线性筛法求欧拉函数φ:(摘自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)多算的。

这道题的代码如下:

#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;
}
感谢各位观看我的博客,希望对您有所帮助,谢谢。
posted @ 2015-08-03 16:40  wlxy  阅读(127)  评论(0编辑  收藏  举报