题目-可见的点

在这里插入图片描述

问题分析

对于任意一个点 ( t ⋅ x 0 , t ⋅ y 0 ) (t \cdot x_0, t \cdot y_0) (tx0,ty0), 斜率 k = y 0 x 0 k = \frac{y_0}{x_0} k=x0y0, 当前点是可见的等价于 ( x 0 , y 0 ) (x_0, y_0) (x0,y0)互质

欧拉函数 ϕ ( i ) \phi (i) ϕ(i) 1 ∼ i 1 \sim i 1i i i i互质的数的个数, 可以提前统计出 ϕ ( n ) \phi(n) ϕ(n), 然后加上坐标轴上的情况

算法步骤

在线性筛法质数过程中同步的统计欧拉函数, 算法时间复杂度 O ( n ) O(n) O(n), 将整个矩形一分为二, 分别累计 t = 1 ∼ 1 , 1 ∼ 2 , 1 ∼ 3 , . . . , 1 ∼ n t = 1 \sim 1, 1 \sim 2, 1\sim 3, ..., 1 \sim n t=11,12,13,...,1n的互质的数的个数(相当于半个矩形), 那么答案就等于 a n s = 2 × t − 1 + 2 ans = 2 \times t - 1 + 2 ans=2×t1+2, 1 1 1 k = 1 k = 1 k=1直线被多算了一次, 2 2 2是坐标轴上的也要统计上

代码实现

如果每次都要调用 i n i t init init函数, 一定要对 s t st st数组和 c n t cnt cnt清零, 否则会造成脏数据(上个用例的数据)的错误计算!!!

#include <bits/stdc++.h>

using namespace std;

const int N = 1010;

int T, n;
int primes[N], cnt;
bool st[N];
int phi[N];

void init(int n) {
   
    phi[1] = 1;
    for (int i = 2; i <= n; ++i) {
   
        if (!st[i]) {
   
            primes[cnt++] = i;
            phi[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; ++j) {
   
            st[i * primes[j]] = true;
            if (i % primes[j]) {
   
                phi[i * primes[j]] = phi[i] * (primes[j] - 1);
            }
            else {
   
                phi[i * primes[j]] = phi[i] * primes[j];
                break;
            }
        }
    }
}

void solve(int i) {
   
    memset(st, false, sizeof st);
    cnt = 0;
    cin >> n;
    init(n);

    int ans = 0;
    for (int i = 1; i <= n; ++i) ans += phi[i];
    ans = 2 * ans - 1 + 2;
    printf("%d %d %d\n", i, n, ans);
}

int main() {
   
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> T;
    for (int i = 1; i <= T; ++i) solve(i);

    return 0;
}

标准的不多次调用 i n i t init init的写法

#include <bits/stdc++.h>

using namespace std;

const int N = 1010;

int T, n;
int primes[N], cnt;
bool st[N];
int phi[N];

void init(int n) {
   
    phi[1] = 1;
    for (int i = 2; i <= n; ++i) {
   
        if (!st[i]) {
   
            primes[cnt++] = i;
            phi[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; ++j) {
   
            st[i * primes[j]] = true;
            if (i % primes[j]) {
   
                phi[i * primes[j]] = phi[i] * (primes[j] - 1);
            }
            else {
   
                phi[i * primes[j]] = phi[i] * primes[j];
                break;
            }
        }
    }
}

void solve(int i) {
   
    cin >> n;

    int ans = 0;
    for (int i = 1; i <= n; ++i) ans += phi[i];
    ans = 2 * ans - 1 + 2;
    printf("%d %d %d\n", i, n, ans);
}

int main() {
   
    ios::sync_with_stdio(false);
    cin.tie(0);

    init(N - 1);
    cin >> T;
    for (int i = 1; i <= T; ++i) solve(i);

    return 0;
}