1. 程式人生 > >[SDOI2008]儀仗隊(歐拉篩裸題)

[SDOI2008]儀仗隊(歐拉篩裸題)

ret 其他人 輸入輸出格式 不同 tex 多次 是否 highlight urn

題目描述

作為體育委員,C君負責這次運動會儀仗隊的訓練。儀仗隊是由學生組成的N * N的方陣,為了保證隊伍在行進中整齊劃一,C君會跟在儀仗隊的左後方,根據其視線所及的學生人數來判斷隊伍是否整齊(如右圖)。 技術分享圖片 現在,C君希望你告訴他隊伍整齊時能看到的學生人數。

輸入輸出格式

輸入格式:

共一個數N

輸出格式:

共一個數,即C君應看到的學生人數。

思路:

典型的歐拉篩

為了幫助萌新,我先從歐拉函數開講

什麽是歐拉函數?

定義:與一個數的約數有且只有1的數(互質)的個數(比如說2有1一個,6有1,5兩個)

性質:積性函數(Phi(i)等於他的所有質因數的phi值的乘積)

為什麽能這麽做呢?

其實這道題求的是有多少種不同的斜率

為什麽呢?

看圖:

技術分享圖片

很顯然,一個斜率上只能看到一個人,該斜率其他人都會被堵得死死的。。。

那麽,每一個獨立的斜率又如何表示呢?

我們用數對(x,y)表示斜率

我們知道,如果x,y不互質,那麽他們可以同時除以他們的最大公約數(設為k),則該斜率可表示為(x/k,y/k)

很顯然會有重復

所以為了避免重復,我們所求的是互質點對的個數

互質點對很顯然就是歐拉函數

這裏我用的是(nlogn)的算法——埃氏篩

從2開始,一個數i如果因數標記為1,則他是素數,他的歐拉函數值為i-1,同時,利用它來更新所有它的倍數的因數標記,如果因數標記大於1,則其不是素數,根據積性函數的性質,Phi[i]=其各因數的乘積,當其含有多次方因子時(比如8=2^3),那麽Phi[i]的值為phi[2]*2*2;

不說了,代碼:

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
long long ll;
long long e[40010];
long long n,ans;
int main()
{
    ans=2;
    cin>>n;
    if(n==1)
    {
        cout<<0;
        return 0;
    }
    for(int i=1;i<=n;++i)
    {
        e[i]=i;
    }
    for(int i=2;i<=n;++i)
    {
        if(e[i]==i)
        {
            for(int j=i;j<=n;j+=i)
            {
                e[j]=e[j]/i*(i-1);
            }
        }
    }
    n--;
    for(int i=2;i<=n;++i)
    {
        ans+=e[i]*2;
    }
    cout<<ans+1;
}        

[SDOI2008]儀仗隊(歐拉篩裸題)