POJ 2478-Farey Sequence(尤拉函式)

kewlgrl發表於2016-03-09
Farey Sequence
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 14071   Accepted: 5567

Description

The Farey Sequence Fn for any integer n with n >= 2 is the set of irreducible rational numbers a/b with 0 < a < b <= n and gcd(a,b) = 1 arranged in increasing order. The first few are 
F2 = {1/2} 
F3 = {1/3, 1/2, 2/3} 
F4 = {1/4, 1/3, 1/2, 2/3, 3/4} 
F5 = {1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5} 

You task is to calculate the number of terms in the Farey sequence Fn.

Input

There are several test cases. Each test case has only one line, which contains a positive integer n (2 <= n <= 106). There are no blank lines between cases. A line with a single 0 terminates the input.

Output

For each test case, you should output one line, which contains N(n) ---- the number of terms in the Farey sequence Fn. 

Sample Input

2
3
4
5
0

Sample Output

1
3
5
9

Source

POJ Contest,Author:Mathematica@ZSU


題意:
給定一個數n,求所有小於等於n的正整數中,有多少對是互質的。

知識點:
尤拉函式。
可以先套尤拉函式模板,然後從1-n列舉,依次使用尤拉函式求出值然後相加。

就像下面這樣:

#include<iostream>
using namespace std;

int oula(int n)
{
    int i,ans=n;
    for(i=2; i*i<=n; ++i)
        if(n%i==0)
        {
            ans-=ans/i;
            while(n%i==0)
                n/=i;
        }
    if(n>1)
        ans-=ans/n;
    return ans;
}

int main()
{
    int n,i;
    while(cin>>n&&n)
    {
        int ans=0;
        for(i=2; i<=n; ++i)
            ans+=oula(i);
        cout<<ans<<endl;
    }

    return 0;
}


但是!!!這種方法會超時!!

由於這種情況下頻繁的使用尤拉函式,所以需要預先打表。
所以,我們要使用遞推求尤拉函式的方法。
預先把所有數的尤拉函式值都置為它本身,定理:如果p是一個正整數而且滿足φ(p)=p-1,則這個數是素數。
在遍歷過程中如果遇到與自身相等的情況,那麼說明該數為素數,改變這個數的尤拉函式值,同時也能把該素因子整除的數改變。其複雜度為O(nlnn)。

AC程式碼如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const long long N=1000000;
long long a[N+5];

int main()
{
    int n,i,j;
    for(i=1; i<=N; ++i)
        a[i]=i;
    for(i=2; i<=N; i+=2)
        a[i]/=2;
    for(i=3; i<=N; i+=2)
        if(a[i]==i)
            for(j=i; j<=N; j+=i)
                a[j]=a[j]/i*(i-1);
    for(i=3; i<=N; ++i)
        a[i]+=a[i-1];
    while(~scanf("%d",&n)&&n)
        printf("%lld\n",a[n]);
    return 0;
}


相關文章