[luogu]P3768 簡單的數學題(莫比烏斯反演,杜教篩)
阿新 • • 發佈:2018-12-13
題意
求,答案膜素數
資料範圍:
題解
設
如果所以尤拉函式和狄利克雷卷積,可以知道(我一開始也沒反應過來,可以設為進一步推導)
,可以整除分塊求,問題就變為化解(特指杜教篩操作)
設,為積性函式,
由杜教篩
那麼
就可以快速求得字首積了(預處理範圍取)
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <unordered_map> using namespace std; using LL = long long; const int MAXN = 8e6 + 5; LL N, P; bool noprime[MAXN]; int prime[MAXN], cnt_p, phi[MAXN]; void Euler_Sieve(int top); LL pre[MAXN]; unordered_map<LL, LL> sum; LL inv_2, inv_6; LL getpre(LL); LL qpow(LL, LL); LL getsum(LL, int); int main(){ cin >> P >> N; inv_2 = (P + 1) / 2, inv_6 = qpow(6, P - 2); Euler_Sieve(MAXN - 5); LL ans = 0; LL l, r; for(l = 1; l <= N; l = r + 1){ r = N / (N / l); LL tmp = getpre(r) - getpre(l - 1); tmp = (tmp % P + P) % P; LL x = getsum(N / l, 3); tmp = tmp * x % P; ans = (ans + tmp) % P; } cout << ans << endl; return 0; } LL getpre(LL n){ if(n <= MAXN - 5) return pre[n] % P; if(sum[n]) return sum[n]; LL l, r, res; res = getsum(n, 3); for(l = 2; l <= n; l = r + 1){ r = n / (n / l); LL tmp = (getsum(r, 2) - getsum(l - 1, 2) + P) % P; res -= getpre(n / l) * tmp % P; res %= P; } res = (res + P) % P; return sum[n] = res; } LL qpow(LL x, LL n){ LL res = 1; while(n){ if(n & 1) res = res * x % P; x = x * x % P; n >>= 1; } return res; } void Euler_Sieve(int top){ int i, j; phi[1] = 1; for(i = 2; i <= top; i++){ if(!noprime[i]) prime[++cnt_p] = i, phi[i] = i - 1; for(j = 1; j <= cnt_p && prime[j] * i <= top; j++){ noprime[prime[j] * i] = true; if(i % prime[j] == 0){ phi[prime[j] * i] = phi[i] * prime[j]; break; } phi[prime[j] * i] = phi[i] * (prime[j] - 1); } } for(j = 1; j <= top; j++) pre[j] = (pre[j - 1] + 1LL * phi[j] * j % P * j % P) % P; } LL getsum(LL n, int op){ n %= P; if(op == 1) return n * (n + 1) % P * inv_2 % P; else if(op == 2) return n * (n + 1) % P * (2 * n + 1) % P * inv_6 % P; else return getsum(n, 1) * getsum(n, 1) % P; }