1. 程式人生 > >洛谷 P2158 [SDOI2008]儀仗隊 解題報告

洛谷 P2158 [SDOI2008]儀仗隊 解題報告

分解 AR AC 判斷 種類 std 求和 輸入輸出 解題報告

P2158 [SDOI2008]儀仗隊

題目描述

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

輸入輸出格式

輸入格式:

共一個數N

輸出格式:

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

說明

對於 100% 的數據,1 ≤ N ≤ 40000


今天看了一天的歐拉函數,明天月考放飛自我了...

對於歐拉函數
將正整數\(N\)用算術基本定理進行分解\(N=\prod_{i=1}^k{c_i}^{m_i}\),\(k\)

\(N\)分解質因數後的質因子種類的個數。
\(φ(N)=N* \prod_{i=1}^{k} (1-\frac{1}{c_i})\)

證明方法需要用到容斥原理。

幾個性質:

  1. \(gcd(a,b)=1\),則\(φ(ab)=φ(a)*φ(b)\)
    積性函數定義啊。

  2. 若質數\(q\)滿足\(q|n\)\(q^2|n\),則\(φ(q)=φ(n/q)*q\)
    代入定義式可以得到

  3. 若質數\(q\)滿足\(q|n\)\(q^2 \nmid n\),則\(φ(q)=φ(n/q)*(q-1)\)
    由積性函數性質得到

  4. \(\sum_{d|n}φ(d)=n\)
    先證明是積性函數,再討論單因子即可

  5. \(φ(n)*n/2=\sum_{d},gcd(d,n)=1\)


    成對存在


在看看這題。

我們以左下角為原點,第一行為\(x\)軸,第一列為\(y\)軸。

則若點\((x,y)\)能被看見,則\((dx,dy)\),\(d \in N^*\)會被遮擋

則點\((x,y)\)能被看見的條件為\(gcd(x,y)=1\),即它們互質。

那麽對此,我們可以將我們要求的轉換為\(\sum_{i=2}^n φ(i)\)

當然這只是右下角的一部分。

加上(0,1),(1,1),(1,0)三個點,最終答案為\(3+2*(\sum_{i=2}^n φ(i))\)


對於歐拉函數的求和,我們可以借助線性篩的思想做到線性的復雜度

可以參考代碼。

code:

#include <cstdio>
const int N=40010;
int v[N],prime[N],eu[N],cnt=0,ans=0,n;
void eular()
{
    for(int i=2;i<=n;i++)
    {
        if(!v[i])
        {
            v[i]=i;
            prime[++cnt]=i;
            eu[i]=i-1;
            ans+=eu[i];
        }
        for(int j=1;j<=cnt;j++)
        {
            int tmp=i*prime[j];
            if(v[i]<prime[j]||tmp>n) break;
            v[tmp]=prime[j];
            eu[tmp]=eu[i]*(i%prime[j]?prime[j]-1:prime[j]);
            ans+=eu[tmp];
        }
    }
}
int main()
{
    scanf("%d",&n);
    n--;
    if(!n) {printf("0\n");return 0;}
    eular();
    printf("%d\n",(ans<<1)+3);
    return 0;
}

2018.5.28

洛谷 P2158 [SDOI2008]儀仗隊 解題報告