CONTENT: 线性筛与积性函数 III
DETAIL: Min_25筛
BB
今天因为BZOJ上多了个测试数据0,调了两个钟 QAQQQQQ
Introduction
- Min_25筛
https://www.cnblogs.com/cjyyb/p/9185093.html
https://lnrbhaw.github.io/2019/01/16/Min-25%E7%AD%9B%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/
https://www.luogu.org/problemnew/solution/P5325
Note
【模板】Min_25筛 - luogu P5325
Description
定义积性函数f(x),且f(p^k)=p^k(p^k−1)(p是一个质数),求
sum(f(x))
对1e9 + 7取模。
Sample Input
10
1000000000
Sample Output
263
710164413
Solution
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = (int)1e6 + 15;
const ll MOD = (ll)1e9 + 7;
const ll inv6 = 166666668;
bool isNotPrime[N];
ll prime[N], tot;
ll sum1[N], sum2[N], g1[N], g2[N], w[N];
ll idx1[N], idx2[N];
int gTot;
ll sqrtN;
inline void init(int n) {
for(int i = 2; i <= n; i++) {
if(!isNotPrime[i]) {
prime[++tot] = i;
sum1[tot] = (sum1[tot - 1] + i) % MOD;
sum2[tot] = (sum2[tot - 1] + (ll)i * i) % MOD;
}
for(int j = 1; i * prime[j] <= n; j++) {
isNotPrime[i * prime[j]] = true;
if(i % prime[j] == 0) {
break;
}
}
}
}
inline void initG(ll n) {
// calculate g1[gTot] = 1 + 2 + 3 + ...
// calculate g2[gTot] = 1^2 + 2^2 + 3^3 + ...
for(ll i = 1, r; i <= n; i = r + 1) {
w[++gTot] = n / i;
r = n / (n / i);
if(w[gTot] <= sqrtN) {
idx1[n / i] = gTot;
} else {
idx2[n / (n / i)] = gTot;
}
ll x = w[gTot] % MOD;
g1[gTot] = (x * (x + 1) / 2 + MOD - 1) % MOD;
g2[gTot] = (x * (x + 1) % MOD * (2 * x + 1) % MOD * inv6 + MOD - 1) % MOD;
}
// enumerate j, then enumerate n
// g(i, j - 1) can be calculated before g(n, j)
for(int i = 1; i <= tot; i++) {
for(int j = 1; j <= gTot && (ll)prime[i] * prime[i] <= w[j]; j++) {
ll k = w[j] / prime[i] <= sqrtN ? idx1[w[j] / prime[i]] : idx2[n / (w[j] / prime[i])];
g1[j] = (g1[j] - (ll)prime[i] * (g1[k] - sum1[i - 1] + MOD) % MOD + MOD) % MOD;
g2[j] = (g2[j] - (ll)prime[i] * prime[i] % MOD * (g2[k] - sum2[i - 1] + MOD) % MOD + MOD) % MOD;
}
}
}
inline ll calcS(ll x, int j, ll n) {
if(prime[j] >= x) {
return 0;
}
ll k = x <= sqrtN ? idx1[x] : idx2[n / x];
ll ans = ((ll)g2[k] - g1[k] - (sum2[j] - sum1[j]) + 2LL * MOD) % MOD;
for(int i = j + 1; i <= tot && (ll)prime[i] * prime[i] <= x; i++) {
for(ll e = 1, pie = prime[i]; pie <= x; pie *= prime[i], e++) {
ll xx = pie % MOD;
ans = (ans + xx * (xx - 1) % MOD * (calcS(x / pie, i, n) + (e != 1))) % MOD;
}
}
return ans;
}
int main() {
ll n;
while(~scanf("%lld", &n)) {
sqrtN = sqrt(n);
init(sqrtN);
initG(n);
printf("%lld\n", (calcS(n, 0, n) + 1) % MOD);
}
}
【模板】杜教筛(Sum) - luogu P4213
Description
求sum(mu(i))与sum(phi(i))
Sample Input
6
1
2
8
13
30
2333
Sample Output
1 1
2 0
22 -2
58 -3
278 -3
1655470 2
Solution
对于莫比乌斯函数,直接直接构造f(x)=-1,这是显然的
对于欧拉函数,直接构造f(x)=x-1,这也是显然的= =
那么就拆分为求g1(x)=sum(1),g2(x)=sum(x)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = (int)1e5 + 15;
const int LIM = (1LL << 31) - 1;
bool isNotPrime[N];
int prime[N];
int tot;
int sum1[N], g1[N];
ll sum2[N], g2[N];
int w[N];
int idx1[N], idx2[N];
int gTot;
int sqrtN;
inline void init(int n) {
tot = 0;
for(int i = 2; i <= n; i++) {
if(!isNotPrime[i]) {
prime[++tot] = i;
sum1[tot] = sum1[tot - 1] + 1;
sum2[tot] = sum2[tot - 1] + i;
}
for(int j = 1; i * prime[j] <= n; j++) {
isNotPrime[i * prime[j]] = true;
if(i % prime[j] == 0) {
break;
}
}
}
}
inline void initG(int n) {
// calculate g1[gTot] = \sum 1
// calculate g2[gTot] = \sum i
gTot = 0;
for(int i = 1, r; i <= n; i = r + 1) {
w[++gTot] = n / i;
r = n / (n / i);
if(n / i <= sqrtN) {
idx1[n / i] = gTot;
} else {
idx2[n / (n / i)] = gTot;
}
int x = w[gTot];
g1[gTot] = x - 1;
g2[gTot] = (ll)x * ((ll)x + 1) / 2 - 1;
if(r == LIM) {
break;
}
}
for(int i = 1; i <= tot; i++) {
for(int j = 1; j <= gTot && prime[i] <= w[j] / prime[i]; j++) {
int k = w[j] / prime[i] <= sqrtN ? idx1[w[j] / prime[i]] : idx2[n / (w[j] / prime[i])];
g1[j] -= (g1[k] - sum1[i - 1]);
g2[j] -= (ll)prime[i] * (g2[k] - sum2[i - 1]);
}
}
}
inline int calcSMu(int x, int j, int n) {
if(prime[j] >= x) {
return 0;
}
int k = x <= sqrtN ? idx1[x] : idx2[n / x];
int ansMu = -(g1[k] - sum1[j]);
for(int i = j + 1; i <= tot && prime[i] <= x / prime[i]; i++) {
ansMu -= calcSMu(x / prime[i], i, n);
}
return ansMu;
}
inline ll calcSPhi(int x, int j, int n) {
if(prime[j] >= x) {
return 0;
}
int k = x <= sqrtN ? idx1[x] : idx2[n / x];
ll ansPhi = g2[k] - g1[k] - (sum2[j] - sum1[j]);
for(int i = j + 1; i <= tot && prime[i] <= x / prime[i]; i++) {
int pie = prime[i];
for(int e = 1; pie <= x; pie *= prime[i], e++) {
ansPhi += 1LL * (pie - pie / prime[i]) * (calcSPhi(x / pie, i, n) + (e != 1));
if(pie > x / prime[i]) {
break;
}
}
}
return ansPhi;
}
int main() {
init(N - 2);
int t;
scanf("%d", &t);
while(t--) {
int n;
scanf("%d", &n);
sqrtN = sqrt(n);
initG(n);
if(n == 0) {
printf("0 0\n");
continue;
}
printf("%lld %d\n", calcSPhi(n, 0, n) + 1, calcSMu(n, 0, n) + 1);
}
}