[SDOI2008]儀仗隊(歐拉函數)

題目

[SDOI2008]儀仗隊c++

解析

這個題,我也不知道他們的soltion是怎麼寫的這麼長的。
咱們發現咱們一次看一條直線上的第一個點,也就是說,若兩個點斜率\(k=\frac{y}{x}\)相同的話,咱們只能看到x,y最小的那個點。
而後根據小學數學,\(\frac{x}{y}=\frac{kx}{ky}(k=1,2,3...)\),也就是說,咱們能看到的點的集合是\(\{(x,y)\mid x⊥y\ \&\ x\in N_+\ \& y\in N_+ \}\),那咱們實際上就是求:對於一個數x,有幾個和他互質的數,也就是求歐拉函數。
咱們觀察一下圖,能夠這樣創建一下座標系

就一目瞭然了,顯然就是求\(3+\sum_{i=3}^{n}\phi(i-1)*2\)git

  • 爲何是\(i-1\)
    由於咱們創建的座標系是從0開始的,題目中是從1開始的。
  • 爲何要\(\times 2\)
    由於咱們求的\(\phi(i-1)\)實際上直線\(y=x\)一側的

最後,特判一下1和2就能夠了。函數

代碼

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, num;
int p[N], phi[N];
bool vis[N];

template<class T>inline void read(T &x) {
    x = 0; int f = 0; char ch = getchar();
    while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    x = f ? -x : x;
    return;
}

void shai(int n) {
    phi[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!vis[i]) p[++num] = i, phi[i] = i - 1;
        for (int j = 1; j <= num; ++j) {
            if (p[j] * i > n) break;
            vis[i * p[j]] = 1;
            if (i % p[j] == 0) {
                phi[i * p[j]] = phi[i] * p[j];
                 break;
            } else phi[i * p[j]] = phi[i] * phi[p[j]];
        }
    }
}

int main() {
    read(n);
    shai(N);
    if (n == 1) {
        printf("1");
        return 0;
    }
    if (n == 2) {
        printf("3\n");
        return 0;
    }
    int ans = 3;
    for (int i = 1; i <= n; ++i) printf("%d : %d\n", i, phi[i]);
    for (int i = 3; i <= n; ++i) ans += phi[i - 1] * 2;
    cout << ans;
    return 0;
}
相關文章
相關標籤/搜索