洛谷題單指南-數學基礎問題-P3601 簽到題

江城伍月發表於2024-04-16

原題連結:https://www.luogu.com.cn/problem/P3601

題意解讀:求l~r範圍內所有 之和,為小於等於的數中,與不互質的數的個數。注意取模。

解題思路:

尤拉函式定義:phi(x) = x * (1-1/p1) * (1-1/p2) *...* (1-1/pn),p1,p2...pn為x的所有質因子

其中:phi(x)表示1~x中所有與x互質的數的個數

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;

typedef long long LL;
const LL MOD = 666623333;
LL l, r;
LL primes[N], cnt, flag[N];
LL phi[N], pb[N]; //phi[x]表示φ(x)尤拉函式的值,pb[i]表示i的大於sqrt(i)的那一個質因數
LL ans;

//埃氏篩,篩1~10^6範圍內所有素數
void getprimes()
{
    for(LL i = 2; i <= 1000000; i++)
    {
        if(!flag[i]) 
        {
            primes[++cnt] = i;
            for(LL j = i + i; j <= 1000000; j += i)
            {
                flag[j] = true;
            }
        }
    }
}

int main()
{
    cin >> l >> r;

    //篩1~sqrt(r)範圍內所有素數
    getprimes();

    //初始化phi,pb
    for(LL i = l; i <= r; i++)
    {
        phi[i - l] = i;
        pb[i - l] = i;
    }

    //計算phi,pb
    for(LL i = 1; i <= cnt && primes[i] * primes[i] <= r; i++)
    {   
        LL p = primes[i];
        LL start = l / p;
        if(l % p != 0) start++;
        for(LL j = start * p; j <= r; j += p) // j是l~r範圍內p的倍數
        {
            phi[j - l] = phi[j - l] / p * (p - 1); //計算素數p對phi[j]的貢獻
            while(pb[j - l] % p == 0) pb[j - l] /= p; //將pb[j]去掉所有p素因子
        }
    }

    for(LL i = l; i <= r; i++)
    {
        if(pb[i - l] != 1) 
        {
            phi[i - l] = phi[i - l] / pb[i - l] * (pb[i - l] - 1);
        }
        ans = (ans + (i - phi[i - l])) % MOD;
    }
    cout << ans;
    return 0;
}

相關文章