洲阁筛

给定一个积性函数$F(n)$,求$\sum_{i = 1}^{n}F(n)$。并且$F(n)$满足在素数和素数次幂的时候易于计算。

显然有:

$\sum_{i = 1}^{n} F(n) = \sum_{i = 1}^{\sqrt{n}}F(i) \left(\sum_{\sqrt{n} < p\leqslant n/i, p\ is\ a\ prime} F(p) \right) + \sum_{i = 1, i\ has\ no\ prime\ factor\ greater\ than\ \sqrt{n}}^{n} F(i)$。

Part 1

第一部分是要求出$\sum_{\sqrt{n}<p \leqslant n/i, p\ is\ a\ prime} F(p)$

假设小于等于$\sqrt{n}$的素数从小到大分别是$P_1, P_2, \cdots, P_{m}$。

设$f_{i, j}$表示$[1, j]$中和前$i$个素数互质的数的函数值和。

当$i = 0$时候想办法计算。

考虑当$i > 0$的时候的转移。考虑从$f_{i - 1, j}$中需要删掉最小质因子等于$P_i$的数的贡献。

所以有转移式子$f_{i, j} = f_{i - 1, j} - F(P_i) f_{i - 1, \left \lfloor j / P_i \right \rfloor}$

如果$F(n)$本身不是完全积性函数,需要把它拆成若干积性函数的和。注意这一部分只用保证素数处取值相同即可。

注意到第一维约有$O\left (\frac{\sqrt{n}}{\log n} \right)$种取值,第二维有$O\left (\sqrt{n}\right)$种取值。暴力计算的复杂度是$O\left (\frac{n}{\log n} \right )$

优化

考虑当$j < P_{i+ 1}$的时候,$f_{i, j} = 1$。考虑把条件放缩成$j < P_i$。

因此,当$P_i \leqslant j < P_{i}^2$的时候$f_{i, j} = f_{i - 1, j} - F(P_i)$。

所以做法是:

  • 维护一个$F(P_i)$的前缀和
  • 考虑转移时的$f_{i - 1, \left \lfloor j / P_i \right \rfloor}$
    • 当$j \geqslant P_{i}^2$的时候暴力计算
    • 当$P_i \leqslant j < P_{i}^2$的时候,需要这样的状态的时候减去一段和就行了。
    • 当$j < P_i$的时候,由于$f_{i, 0} = 0$,所以这一部分的值不会改变。

所以对于每个$j$,有效的状态只有$O\left (\frac{\sqrt{j}}{\log j} \right )$。

时间复杂度为:$\sum_{i = 1}^{\sqrt{n}} O \left (\frac{\sqrt{i}}{\log i} \right ) + \sum_{i = 1}^{\sqrt{n}} O\left ( \frac{\sqrt{n/i}}{\log {n/i}}\right)$

由于第一部分显然小于第二部分,所以只用考虑第二部分的和。

所以有:$\sum_{i = 1}^{\sqrt{n}}O \left (\frac{\sqrt{n/i}}{\log n - \log i}\right)$

由于$\log i \leqslant \log \sqrt{n} = \frac{1}{2}\log n$

所以:$\sum_{i = 1}^{\sqrt{n}}O \left (\frac{\sqrt{n/i}}{\frac{1}{2}\log n}\right) = \sum_{i = 1}^{\sqrt{n}}O\left (\frac{\sqrt{n / i}}{\log n}\right) = O\left ( \frac{n^{3/4}}{\log n}\right)$

Part 2

这一部分是要求出$\sum_{i = 1, i\ has\ no\ prime\ factor\ greater\ than\ \sqrt{n}}^{n} F(i)$

假设小于等于$\sqrt{n}$的素数从小到大分别是$P_1, P_2, \cdots, P_{m}$。

设$g_{i, j}$表示在$[1, j]$中,质因子只包含$P_{i}, P_{i + 1}, \cdots, P_{m}$的数的函数值的和。

转移考虑枚举当前质数$P_i$的指数。所以有:$g_{i, j} = g_{i + 1, j} + \sum_{e = 1}^{\log_{P_i} j} F(P_{i}^{e}) g_{i + 1, \lfloor j / P_i^e\rfloor}​$

对于时间复杂度,考虑对于每一个$j$的转移的枚举量,可以得到大概是$O(\frac{\sqrt{j}}{\log j})$。(不会积分,告辞)

和Part 1一样,得到暴力计算这一部分的复杂度是$O(\frac{n}{\log n})$。

优化

因为质因子是从大到小枚举的,所以当$j < P_{i}$的时候,$g_{i, j} = 1$。

所以当满足$P_i \leqslant j < P_{i}^2$,满足$g_{i, j} = g_{i + 1, j} + F(P_i)$。

和Part 1一样,分成三段,一段暴力转移,一段需要时前缀和,一段不需要维护。

复杂度也是同样的计算方法

 /**
* SPOJ
* Problem#DIVCNT3
* Accepted
* Time: 35190ms
* Memory: 33792k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; template <typename T>
void pfill(T* pst, const T* ped, T val) {
for ( ; pst != ped; *(pst++) = val);
} #define ll long long typedef class Euler {
public:
int num;
boolean *vis;
int *pri, *d3, *mp; Euler(int n) : num() {
d3 = new int[(n + )];
mp = new int[(n + )];
pri = new int[(n + )];
vis = new boolean[(n + )];
pfill(vis, vis + n + , false);
d3[] = ;
for (int i = ; i <= n; i++) {
if (!vis[i]) {
d3[i] = , pri[num++] = i, mp[i] = ;
}
for (int j = , _ = n / i, x; j < num && pri[j] <= _; j++) {
vis[x = pri[j] * i] = true;
if (!(i % pri[j])) {
d3[x] = (d3[i / mp[i]] + ) * d3[mp[i]];
mp[x] = mp[i];
break;
} else {
mp[x] = i, d3[x] = d3[i] << ;
}
}
}
}
~Euler() {
delete[] mp;
delete[] vis;
delete[] d3;
delete[] pri;
}
} Euler; const int N = ; Euler *_euler; int T;
vector<ll> ns; ll maxn, D; int cnt_prime;
int *pri, *d3; inline void init() {
scanf("%d", &T);
for (ll x; T--; ) {
scanf("%lld", &x);
ns.push_back(x);
maxn = max(maxn, x);
}
D = sqrt(maxn + 0.5) + ;
while (D * 1ll * D <= maxn)
D++;
_euler = new Euler(D + );
cnt_prime = _euler->num;
pri = _euler->pri, d3 = _euler->d3;
} ll n;
int cnt_P[N];
int range0[N], range1[N];
ll f0[N], f1[N], g0[N], g1[N]; void precalc() {
for (int i = ; i < D; i++) {
range0[i] = range0[i - ];
while (pri[range0[i]] * 1ll * pri[range0[i]] <= i) {
range0[i]++;
}
}
for (int i = D - ; i; i--) {
ll y = n / i;
range1[i] = range1[i + ];
while (pri[range1[i]] * 1ll * pri[range1[i]] <= y) {
range1[i]++;
}
}
pfill(cnt_P, cnt_P + D, );
for (int i = ; pri[i] < D; i++) {
cnt_P[pri[i]]++;
}
for (int i = ; i < D; i++) {
cnt_P[i] += cnt_P[i - ];
}
} int nump;
ll get_value_f(int i, ll j) {
if (j >= D) {
int rj = n / j;
return f1[rj] + (max(, nump - max(range1[rj], i)) << );
}
return f0[j] + (max(, cnt_P[j] - max(range0[j], i)) << );
} void calculate_f() {
for (nump = ; pri[nump] < D; nump++);
for (int i = ; i < D; i++) {
f0[i] = , f1[i] = ;
}
for (int i = nump - ; ~i; i--) {
for (int j = ; j < D && i < range1[j]; j++) {
ll m = n / j, coef = ;
while (m /= pri[i]) {
f1[j] += (coef += ) * get_value_f(i + , m);
}
}
for (int j = D - ; j && i < range0[j]; j--) {
ll m = j, coef = ;
while (m /= pri[i]) {
f0[j] += (coef += ) * get_value_f(i + , m);
}
}
}
for (int i = ; i < D; i++) {
f1[i] = get_value_f(, n / i);
}
for (int i = ; i < D; i++) {
f0[i] = get_value_f(, i);
}
} ll get_value_g(int i, ll j) {
if (j >= D) {
int rj = n / j;
return g1[rj] - max(, i - range1[rj]);
}
return g0[j] - max(, min(i, cnt_P[j]) - range0[j]);
} void calculate_g() {
for (int i = ; i < D; i++) {
g0[i] = i, g1[i] = n / i;
}
int cp = ;
for (int i = ; pri[i] < D; i++, cp++) {
for (int j = ; j < D && i < range1[j]; j++) {
g1[j] -= get_value_g(i, n / j / pri[i]);
}
for (int j = D - ; j && i < range0[j]; j--) {
g0[j] -= get_value_g(i, j / pri[i]);
}
}
for (int i = ; i < D; i++) {
(g1[i] = get_value_g(cp, n / i) - ) <<= ;
}
for (int i = ; i < D; i++) {
(g0[i] = get_value_g(cp, i) - ) <<= ;
}
} void Solve(ll _n) {
n = _n;
D = sqrt(n + 0.5) + ;
while (D * 1ll * D <= n)
D++;
precalc();
calculate_g();
calculate_f();
ll ans = f1[];
for (int i = ; i < D; i++) {
ans += d3[i] * g1[i];
// cerr << d3[i] << " " << g1[i] << '\n';
}
printf("%lld\n", ans);
} inline void solve() {
for (int i = ; i < (signed) ns.size(); i++) {
Solve(ns[i]);
}
} int main() {
init();
solve();
return ;
}

洲阁筛

Min25筛

Part 1

假设小于等于$\sqrt{n}$的素数从小到大分别是$P_1, P_2, \cdots, P_{m}$。

设$g_{i, j} = \sum_{k = 2}^{j} [k的最小质因子大于P_i或者k是质数] F(k)$

转移式子:

$$g_{i, j} =
\begin{cases}g_{i - 1, j} - F(P_i)(g_{i - 1, \lfloor j / P_i\rfloor} - g_{i - 1, P_i - 1}) & (j \geqslant P_i^2) \\ 
g_{i - 1, j} & (1 \leqslant j < P_i^2)
\end{cases}
$$

和洲阁筛类似,不过第一种情况还需要抠掉素数的贡献。

这里也要求$F$是一个完全积性函数。

我们考虑求出$1, 2, \cdots, \sqrt{n}, \lfloor n / \sqrt{n}\rfloor, \cdots, \lfloor n / 2\rfloor, n$处的值。

Part 2

这里考虑计算$S(n, i) = \sum_{i = 2}^{n}[n的最小质因子大于等于P_i]F(n)$。

那么显然答案等于$S(n, 1) + F(1)$。

这里简单粗暴一点,如果是素数,那么可以用第一部分计算的答案再减去某个前缀和得到,否则枚举这个合数的最小质因子。不难得到这样一个式子:

$$
S(n, i) = g_{m, n} - \sum_{j = 1}^{i - 1}F(P_j) + \sum_{j = i \wedge P_j^2 \leqslant n}\sum_{e = 1\wedge P_{j}^{e + 1}\leqslant n} F(P_{j}^{e}) S(\lfloor n/P_{j}^e\rfloor, j + 1) + F(P_{j}^{e + 1})
$$

前一半是计算素数的贡献。

考虑计算合数的贡献,后一半是先枚举最小质因子,因为它是一个合数最小质因子,所以$p^2 \leqslant n$

$p^{e + 1} \leqslant n$是类似的原因。

时间复杂度被证明为是$O(\frac{n}{Poly(\log n)})$。

(似乎目前min_25在$10^{13}$范围内吊打其他筛)

/**
* loj
* Problem#6053
* Accepted
* Time: 332ms
* Memory: 2684k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; #define ll long long void exgcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1, y = 0;
} else {
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
} int inv(int a, int n) {
int x, y;
exgcd(a, n, x, y);
return (x < 0) ? (x + n) : (x);
} const int Mod = 1e9 + 7; template <const int Mod = :: Mod>
class Z {
public:
int v; Z() : v(0) { }
Z(int x) : v(x){ }
Z(ll x) : v(x % Mod) { } friend Z operator + (const Z& a, const Z& b) {
int x;
return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
}
friend Z operator - (const Z& a, const Z& b) {
int x;
return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
}
friend Z operator * (const Z& a, const Z& b) {
return Z(a.v * 1ll * b.v);
}
friend Z operator ~(const Z& a) {
return inv(a.v, Mod);
}
friend Z operator - (const Z& a) {
return Z(0) - a;
}
Z& operator += (Z b) {
return *this = *this + b;
}
Z& operator -= (Z b) {
return *this = *this - b;
}
Z& operator *= (Z b) {
return *this = *this * b;
}
friend boolean operator == (const Z& a, const Z& b) {
return a.v == b.v;
}
}; Z<> qpow(Z<> a, int p) {
Z<> rt = Z<>(1), pa = a;
for ( ; p; p >>= 1, pa = pa * pa) {
if (p & 1) {
rt = rt * pa;
}
}
return rt;
} typedef Z<> Zi; const Zi inv2 ((Mod + 1) >>1); const int Dmx = 1e5 + 5; ll n;
int D;
int pnum;
int pri[Dmx], sf[Dmx]; void Euler(int n) {
static bitset<Dmx + 23> vis;
for (int i = 2; i <= n; i++) {
if (!vis.test(i)) {
pri[pnum++] = i;
}
for (int *p = pri, *_ = pri + pnum, x; p != _ && (x = *p * i) <= n; p++) {
vis.set(x);
if (!(i % *p)) {
break;
}
}
}
for (int i = 1; i <= pnum; i++) {
sf[i] = sf[i - 1] + (pri[i - 1] ^ 1);
}
} template <typename T>
class SieveArray {
public:
ll n;
vector<T> a0;
vector<T> a1; void init(ll n, int D) {
this->n = n;
a0.assign(D, 0);
a1.assign(D, 0);
} T& operator [] (ll p) {
return (p >= (signed) a0.size()) ? a1[n / p] : a0[p];
}
}; SieveArray<int> range;
SieveArray<Zi> f0, f1; Zi S(ll n, int m) {
if (pri[m] > n) {
return 0;
}
Zi rt = f1[n] - sf[m];
for (int j = m; j < pnum && 1ll * pri[j] * pri[j] <= n; j++) {
int p = pri[j];
ll nn = n, p2 = 1ll * p * p;
for (int e = 1; p2 <= nn; e++) {
rt += S(nn /= p , j + 1) * (p ^ e) + (p ^ (e + 1));
}
}
return rt;
} int main() {
scanf("%lld", &n);
D = sqrt(D + 0.5) + 1;
while (1ll * D * D <= n)
D++;
Euler(D + 3);
range.init(n, D);
f0.init(n, D);
f1.init(n, D);
ll t = 0;
range[0] = 0;
for (int i = 1; i < D; i++) {
while (t * t <= i)
t++;
range.a0[i] = t;
}
t = 0;
for (int i = D; --i; ) {
ll v = n / i;
while (t * t <= v)
t++;
range.a1[i] = t;
}
for (int i = 1; i < D; i++) {
f0.a0[i] = i - 1;
f1.a0[i] = ((Zi(i) * (i + 1)) * inv2) - 1;
ll v = n / i;
f0.a1[i] = v - 1;
f1.a1[i] = ((Zi(v) * (v + 1)) * inv2) - 1;
}
for (int i = 0; i < pnum; i++) {
int p = pri[i];
if (p >= D) {
break;
}
ll v;
for (int j = 1; j < D && p < range.a1[j]; j++) {
v = n / (1ll * j * p);
f0.a1[j] -= f0[v] - f0.a0[p - 1];
f1.a1[j] -= (f1[v] - f1.a0[p - 1]) * p;
}
for (int j = D; p < range.a0[--j]; ) {
f0.a0[j] -= f0.a0[j / p] - f0.a0[p - 1];
f1.a0[j] -= (f1.a0[j / p] - f1.a0[p - 1]) * p;
}
}
for (int i = 1; i < D; i++) {
f1.a0[i] -= f0.a0[i];
f1.a0[i] += (i >= 2) * 2;
f1.a1[i] -= f0.a1[i];
f1.a1[i] += (2 * i <= n) * 2;
}
Zi ans = S(n, 0) + 1;
printf("%d\n", ans.v);
return 0;
}

洲阁筛 & min_25筛学习笔记的更多相关文章

  1. [复习]莫比乌斯反演,杜教筛,min_25筛

    [复习]莫比乌斯反演,杜教筛,min_25筛 莫比乌斯反演 做题的时候的常用形式: \[\begin{aligned}g(n)&=\sum_{n|d}f(d)\\f(n)&=\sum_ ...

  2. [BZOJ4916]神犇和蒟蒻 杜教筛/Min_25筛

    题目大意: 给定\(n\le 10^9\),求: 1.\(\sum_{i=1}^n\mu(i^2)\) 2.\(\sum_{i=1}^n\varphi(i^2)\) 解释 1.\(\sum_{i=1} ...

  3. 杜教筛&min_25筛复习

    杜教筛 适用条件 你要能构造出\(g(x),h(x)\),使得\(h=f*g\). \(G(x),H(x)\)的值可以快速计算. 过程 我们要求的是\(F(n)=\sum_{i=1}^{n}f(i)\ ...

  4. 【XSY3042】石像 拓扑排序 状压DP 洲阁筛

    题目大意 有 \(n\) 个整数 \(a_1,a_2,\ldots,a_n\),每个数的范围是 \([1,m]\).还有 \(k\) 个限制,每个限制 \(x_i,y_i\) 表示 \(a_{x_i} ...

  5. min_25筛入门

    目录 1.什么是min_25筛 2.前置知识 2.1.数论函数 2.2.埃拉托色尼筛 2.3.欧拉筛 3.min_25筛 3.1.计算质数贡献 3.2.计算总贡献 3.3.实现 4.例题 4.1.[L ...

  6. 【51NOD1847】奇怪的数学题 min_25筛

    题目描述 记\(sgcd(i,j)\)为\(i,j\)的次大公约数. 给你\(n\),求 \[ \sum_{i=1}^n\sum_{j=1}^n{sgcd(i,j)}^k \] 对\(2^{32}\) ...

  7. 51nod1847 奇怪的数学题 (Min_25筛+第二类斯特林数)

    link \(\sum_{i=1}^n\sum_{j=1}^n\mathrm{sgcd}(i,j)^k=\sum_{p=1}^ns(p)^k\sum_{i=1}^n\sum_{j=1}^n[\gcd( ...

  8. HTTP 1.1学习笔记

    前言 由于HTTP 1自身的局限性,它不能很好的为用户提供性能良好的WEB服务.于1999年6月正式发布了HTTP1.1标准REC2616,它厘清了之前版本中很多有歧义的地方,而且还新增了很多重要的优 ...

  9. Min_25筛 学习笔记

    这儿只是一个简单说明/概括/总结. 原理见这: https://www.cnblogs.com/cjyyb/p/9185093.html https://www.cnblogs.com/zhoushu ...

随机推荐

  1. How to disable transparent hugepages (THP) on Red Hat Enterprise Linux 7

    How to disable transparent hugepages (THP) on Red Hat Enterprise Linux 7 $ Solution 已验证 - 已更新2017年六月 ...

  2. linux自定义开机自启多个服务的脚本

    linux服务器重启后,每次要启动redis.ftp.tomcat等应用总是很麻烦,于是写了一个自定义脚本,在开机或重启的时候,自动启动多个服务.应用. 很简单,写脚本.设置开机启动.   第一步.准 ...

  3. numpy(三)

    广播: x= np.arange(12).reshape((3,4)) a= np.arange(3) b=np.arange(3)[;,np.newaxis] c=a+b a,b会扩散成公共的形状进 ...

  4. 红黑树与AVL特性

    红黑树:比较平衡的二叉树,没有一条路径会比其他路径长2倍,因而是近似平衡的.所以相对于严格要求平衡的AVL树来说,它的旋转保持平衡次数较少.插入删除次数多的情况下我们就用红黑树来取代AVL. 红黑树规 ...

  5. Python3.0科学计算学习之函数

    函数 函数允许程序的控制在不同的代码片段之间切换,函数的重要意义在于可以在程序中清晰地分离不同的任务,将复杂的问题分解为几个相对简单的子问题,并逐个解决.即"分而治之". Pyth ...

  6. eval() 和 int()区别,以及eval作用

    eval()方法作用是将数据转换回原本的类型 a = str(list) type(a)--->str eval(a) type(a)--->list

  7. mat-form-field must contain a MatFormFieldControl错误的解决方法

    下面的代码竟然出错了: <mat-form-field> <input matInput placeholder="输入名称"> </mat-form ...

  8. #WEB安全基础 : HTTP协议 | 0x9 GET和POST请求以及请求URI的方式

    请求URI的方式 1.URI为完整的请求URI GET http://hackr.jp/index.htm HTTP/1.1 2.在首部字段Host中写明域名或IP地址 GET/index.htm H ...

  9. Oracle中hex和raw的相互转换

    可以参考以下语句: select hextoraw(rawtohex('你好')) from dual select utl_raw.cast_to_varchar2(hextoraw('E4BDA0 ...

  10. Django框架详细介绍---AJAX

    一.概述 1.什么是JSON JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 JSON 独立于语言 * ...