当前位置 博文首页 > ttoobne:洛谷P2158 [SDOI2008]仪仗队 (线性筛欧拉函数求前缀和

    ttoobne:洛谷P2158 [SDOI2008]仪仗队 (线性筛欧拉函数求前缀和

    作者:[db:作者] 时间:2021-08-30 10:38

    题目链接

    题解:

    由题意可知,从左下角的点到其他所有点连成的不同斜率的边数即为所求。要求得边长 y / x 不同的数量( y < x),则求与 x 互质的数的个数 *2+3 即可(因为只求出了一个三角形的答案数量,需要*2来求正方形矩阵的答案数量,+3是有三个特殊的边,即两条 y / x == 0 以及一条 y / x == 1)。由于边长为 n?的边的答案包含了边长为 n - 1 的边的答案,所以求个前缀和即可。最后由于他给的是点数,所以求出的前缀和下标必须减一(点数比边长多一)。

    代码:

    #include <cstdio>
    #include <cmath>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <map>
    #include <set>
    #include <bitset>
    using namespace std;
    
    typedef long long ll;
    #define int ll
    #define INF 0x3f3f3f3f3f3f3f3f
    #define MAXM 200000 + 10
    #define MAXN 40000 + 10
    const ll mod = 1e9 + 7;
    #define P pair<int, int>
    #define fir first
    #define sec second
    
    int n;
    int phi[MAXN];
    int prime[MAXN], judge[MAXN], cnt;
    
    void euler()
    {
        phi[1] = 0;
        for(int i = 2; i < MAXN; i ++) {
            if(!judge[i]) {
                prime[++cnt] = i;
                phi[i] = i - 1;
            }
            for(int j = 1; j <= cnt && prime[j] * i < MAXN; j ++) {
                judge[i*prime[j]] = 1;
                if(i % prime[j] == 0) {
                    phi[i*prime[j]] = phi[i] * prime[j];
                    break;
                }
                else phi[i*prime[j]] = phi[i] * phi[prime[j]];
            }
        }
        phi[1] = 0;
        for(int i = 2; i < MAXN; i ++) {
            phi[i] += phi[i-1];
        }
    }
    
    signed main()
    {
        euler();
        cin >> n;
        if(n == 1) cout << 0 << endl;
        else cout << (phi[n-1] * 2 + 3)<< endl;
    }
    
    /*
    
    The WAM is F**KING interesting .
    
    */
    

    ?

    cs