首页 > 其他分享 >一个看起来不错的筛子

一个看起来不错的筛子

时间:2024-04-22 20:56:45浏览次数:9  
标签:筛子 看起来 int s2 s1 i64 k1 不错 id

前置知识

powerful number

定义:\(\text{powerful number}\) 是没有 \(1\) 次质因子的数,也简称为 \(\text{PN}\)。

结论:\(n\) 以内的 \(\text{PN}\) 个数为 \(O(\sqrt n)\)。

证明

所有 \(\text{PN}\) 必然可表示成 \(a^2b^3\) 的形式。

那么:

\[\sum_{a=1}^{\sqrt n}(\frac{n}{a^2})^{\frac{1}{3}}=\sqrt n \]

构造

构造 \(G(p^k)=F(p)^k,G\times H=F\),可以注意到 \(G(P)\) 为完全积性函数。

那么:

\[\begin{aligned} F(p)&=G(1)H(p)+H(1)G(p)\\ &=G(p)+H(p) \end{aligned}\]

所以,\(H(p)=0\)。

\[\begin{aligned} \sum_{i=1}^n F(i)&=\sum_{i=1}^n\sum_{j|i}G(j)H(\frac{i}{j})\\ &=\sum_{i=1}^nH(i)\sum_{j=1}^{\frac{n}{i}}G(j)\\ &=\sum_{i=1}^n[i\in PN]H(i)SG_{\frac{n}{i}}\\ \end{aligned}\]

其中:

\[\begin{aligned} H(p)&=0\\ H(p^2)&=F(p^2)-F(p)^2\\ H(p^3)&=F(p^3)-F(p)F(p^2)\\ H(p^k)&=F(p^k)-F(p)F(p^{k-1}) \end{aligned}\]

所以,我们只需要求出 \(G\) 的块筛即可。

块筛

考虑两种方式。

法一

若 \(G\) 可杜教筛。

可以直接使用杜教筛。

此时,这个筛法就是常称的 \(\text{PN}\) 筛。

法二

若 \(F(p)\) 为一个低次多项式。

考虑 \(S(n,a)\)。

\[\begin{aligned} S(n,a)&=\sum_{i=1}^n[i\in P ~or~ min_i > P_a] G(i)\\ &=S(n,a-1)-g(p_a)(S(\frac{n}{P_a},a-1)-S(P_a-1,a-1))\\ S(n,a-1)&=S(n,a)+g(p_a)(S(\frac{n}{P_a},a-1)-S(P_a-1,a-1))\\ \end{aligned}\]

要求:\(G(x)\) 为完全积性函数。

若 \(\sum_{i=1}^n [i\in P]G(x)\) 很好求出,那么直接用第二个递推式即可。

否则,将多项式 \(G(x)\) 的每一项分别提出来,跑第一个递推式,合并后再用第二个递推式即可。

本质是 \(\text{min-25}\) 筛的前半部分。

完美利用了 \(G(x)\) 的性质。

个人更加推荐法二,这也可以看出这个筛法极强的拓展性。

速度

考虑 \(\text{PN}\) 的过程复杂度为 \(O(\sqrt n)\)。

块筛的过程要么是 \(O(n^{\frac{2}{3}})\) 或者 \(O(\frac{n^{\frac{3}{4}}}{\log n})\)(很可能不准)。

实际效率上比普通 \(\text{min-25}\) 筛快一点(板子题)。

\(10^{10}\):\(0.2s\)。

\(10^{11}\):\(0.6s\)。

\(10^{12}\):\(3.0s\)。

代码难度个人认为比较简单,与杜教筛难度近似,感觉可以作为 \(\text{min-25}\) 筛的上位替代。

例题

P4213 【模板】杜教筛

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

using i64 = long long;

const int N = 1e5 + 10;

i64 n, ans1, ans2, w[N];
i64 s1[N], s2[N], p1[N], p2[N];
int m, ct, tt, p[N], v[N], d1[N], d2[N];

inline void init_all(int m = N - 10) {
  for (int i = 2; i <= m; i++) {
    if (!v[i]) p[++ct] = i, p1[ct] = 1 + p1[ct - 1], p2[ct] = i + p2[ct - 1];
    for (int j = 1; j <= ct && p[j] * i <= m; j++) {
      v[p[j] * i] = 1; if (i % p[j] == 0) break;
    }
  }
}
inline int get(i64 x) { return (x <= m ? d1[x] : d2[n / x]); }
inline void init() {
  m = sqrt(n) + 100, ct = tt = ans1 = ans2 = 0;
  for (i64 l = 1, r; l <= n; l = r + 1) {
    r = (n / (n / l)), w[++tt] = n / l;
    w[tt] <= m ? d1[w[tt]] = tt : d2[r] = tt;
    s1[tt] = w[tt], s2[tt] = (w[tt] + 1) * w[tt] / 2;
    s1[tt]--, s2[tt]--;
  }
  while (1ll * p[ct + 1] * p[ct + 1] <= n) ct++;
  for (int i = 1; i <= ct; i++) {
    const i64 k1 = p[i];
    const i64 k2 = k1 * k1;
    int lim = 0;
    while (lim < tt && k2 <= w[lim + 1]) lim++;
    for (int j = 1; j <= lim; j++) {
      if (k2 > w[j]) break;
      int id = get(w[j] / k1);
      s1[j] = (s1[j] - (s1[id] - p1[i - 1]));
      s2[j] = (s2[j] - k1 * (s2[id] - p2[i - 1]));
    }
  }
  for (int i = 1; i <= tt; i++) s1[i] = -s1[i], s2[i] = s2[i] + s1[i];
  for (int i = 1; i <= tt; i++) p1[i] = -p1[i], p2[i] = p2[i] + p1[i];
  for (int i = ct; i >= 1; i--) {
    const i64 k1 = p[i];
    const i64 k2 = k1 * k1;
    int lim = 0;
    while (lim < tt && k2 <= w[lim + 1]) lim++;
    for (int j = lim; j >= 1; j--) {
      int id = get(w[j] / k1);
      s1[j] = (s1[j] + -1 * (s1[id] - p1[i - 1]));
      s2[j] = (s2[j] + (k1 - 1) * (s2[id] - p2[i - 1]));
    }
  }
  for (int i = 1; i <= tt; i++) s1[i]++, s2[i]++;
  for (int i = 1; i <= tt; i++) p2[i] = p2[i] - p1[i], p1[i] = -p1[i];
}
inline void dfs(int now, i64 cur, i64 h1, i64 h2, i64&ans1, i64&ans2) {
  ans1 = (ans1 + h1 * s1[get(n / cur)]);
  ans2 = (ans2 + h2 * s2[get(n / cur)]);
  for (int i = now; i <= ct; i++) {
    const i64 k = p[i];
    if (k * k > n / cur) break;
    for (i64 x = k * k, y = 1, z = 2; x * cur <= n; x = x * k, y = y * k, z++) {
      dfs(i + 1, cur * x, h1 * (z == 2 ? -1 : 0), h2 * (k - 1) * y, ans1, ans2);
    }
  }
}

int main() {
  int t;
  cin >> t, init_all();
  while (t--) {
    cin >> n, init();
    dfs(1, 1, 1, 1, ans1, ans2);
    cout << ans2 << " ";
    cout << ans1 << "\n";
    for (int i = 1; i <= tt; i++) s1[i] = s2[i] = d1[i] = d2[i] = w[i] = 0;
  }
  return 0;
}

P5325 【模板】Min_25 筛

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

using i64 = long long;

const int N = 1e6 + 10;
const int mod = 1e9 + 7;

i64 n, ans, w[N];
i64 s1[N], s2[N], p1[N], p2[N];
int m, ct, tt, p[N], v[N], d1[N], d2[N];

inline int get(i64 x) { return (x <= m ? d1[x] : d2[n / x]); }
inline void init() {
  m = sqrt(n) + 100;
  for (i64 l = 1, r; l <= n; l = r + 1) {
    r = (n / (n / l)), w[++tt] = n / l;
    w[tt] <= m ? d1[w[tt]] = tt : d2[r] = tt;
    s1[tt] = (__int128)(w[tt] + 1) * w[tt] * 500000004 % mod;
    s2[tt] = (__int128)(2 * w[tt] + 1) * s1[tt] * 333333336 % mod;
    s1[tt]--, s2[tt]--;
  }
  for (int i = 2; i <= m; i++) {
    if (!v[i]) p[++ct] = i, p1[ct] = (i + p1[ct - 1]) % mod, p2[ct] = (1ll * i * i + p2[ct - 1]) % mod;
    for (int j = 1; j <= ct && p[j] * i <= m; j++) {
      v[p[j] * i] = 1;
      if (i % p[j] == 0) break;
    }
  }
  for (int i = 1; i <= ct; i++) {
    const i64 k1 = p[i];
    const i64 k2 = k1 * k1;
    int lim = 0;
    while (lim < tt && k2 <= w[lim + 1]) lim++;
    for (int j = 1; j <= lim; j++) {
      if (k2 > w[j]) break;
      int id = get(w[j] / k1);
      s1[j] = (s1[j] - k1 % mod * (s1[id] - p1[i - 1])) % mod;
      s2[j] = (s2[j] - k2 % mod * (s2[id] - p2[i - 1])) % mod;
    }
  }
  for (int i = 1; i <= tt; i++) s1[i] = (s2[i] - s1[i]) % mod;
  for (int i = 1; i <= ct; i++) p1[i] = (p2[i] - p1[i]) % mod;
  for (int i = ct; i >= 1; i--) {
    const i64 k1 = p[i];
    const i64 k2 = k1 * k1;
    int lim = 0;
    while (lim < tt && k2 <= w[lim + 1]) lim++;
    for (int j = lim; j >= 1; j--) {
      int id = get(w[j] / k1);
      s1[j] = (s1[j] + k1 * (k1 - 1) % mod * (s1[id] - p1[i - 1])) % mod;
    }
  }
  for (int i = 1; i <= tt; i++) s1[i]++;
}
inline void dfs(int now, i64 cur, i64 h, i64&ans) {
  ans = (ans + h * s1[get(n / cur)]) % mod;
  for (int i = now; i <= ct; i++) {
    const i64 k = p[i];
    if (k * k > n / cur) break;
    for (i64 x = k * k, y = k; x * cur <= n; x = x * k, y = y * k) {
      dfs(i + 1, cur * x, (__int128)h * x * (y + k - 2) % mod, ans);
    }
  }
}

int main() {
  cin >> n, init();
  dfs(1, 1, 1, ans);
  cout << (ans + mod) % mod << "\n";
  return 0;
}

标签:筛子,看起来,int,s2,s1,i64,k1,不错,id
From: https://www.cnblogs.com/JiaY19/p/18151514

相关文章

  • 筛子题
    T1Statement求出\(\gcd(n,k)\)的线性筛递推式,并证明复杂度是线性的。Solution\[\gcd(n,k)=\begin{cases}1&(n=1)\\\gcd(\fracn{P(n)},k)\cdotP(n)&(\gcd(\fracn{P(n)},k)\cdotP(n)\midk)\\\gcd(\fracn{P(n)},k)&\text{else}\end{cases}......
  • 一款还不错的文档系统
    一款还不错的文档系统功能不复杂,如果不会就去看看官方的说明吧地址:https://mindoc.com.cn/docs/mindochelp参考文档mindoc-org/mindoc:Golang实现的基于beego框架的接口在线文档管理系统地址:https://github.com/mindoc-org/mindocMinDoc文档管理系统-PoweredbyMinDoc......
  • JS代码混淆器:iPaGuard — 让你的代码看起来令人头大
     在当今互联网时代,JavaScript作为一种广泛应用的编程语言,扮演着至关重要的角色。然而,随着网络技术的不断发展,JavaScript代码也面临着日益增加的安全威胁。为了保护JavaScript代码免受未经授权的复制、修改和逆向工程,开发者需要借助专业的工具和技术。其中,iPaGuard就是一款......
  • 一些不错的历史大题
    4.101感觉有点像是马克思韦伯所说的吧认为这个宗教是资本主义的一种精神动力(?比较反唯物史观,不过今天的西方确实实力衰弱,国际也需要建立政治经济新秩序2根据材料信息并结合所学知识,概括其展示的中华文化内涵,并为该组藏品写一段展览序言。复习下中华优秀传统文化的内涵还......
  • 【AI】『Suno』哎呦不错呦,AI界的周董,快来创作你的歌曲吧!
    前言......
  • 分享几个非常不错嵌入式开源项目,一定不要错过
    大家好,我是知微!经常有小伙伴后台私信我:有没有好的开源项目推荐怎么样才能提升自己的编程能力那么这篇文章就推荐几个还不错的开源项目,感兴趣的小伙伴可以学习一下!日志库EasyLoggerhttps://github.com/armink/EasyLogger开发一个项目,如果没有日志的记录,当遇到问题需要分......
  • 推荐最近在使用的还不错的一款逻辑分析仪
    作为一名嵌入式软件/硬件工程师,要会使用各种仪表仪器,尤其示波器、逻辑分析仪,这两个仪器可以监测各种数据线、信号线波形,可以帮我们快速定位产品问题,缩短开发周期。今天一口君安利一款非常不错的逻辑分析仪:kingstLA5016这款仪器非常容易上手,尤其在一些常见的协议解析这块,表现......
  • 介绍一款非常不错的录像软件
    介绍一款非常不错的录像软件。支持很多录音格式,有AVI,MP4,MOV,TS,VOB等,你也可以自定义设置影片的FPS和比特率。如果你想长时间的录制视频,影片大小可支持4个G的超大文件录制。支持全屏幕录制,也支持自定义范围录制,你可通过调节录像框来决定录像的范围,将不想要录制的地方隐藏......
  • 如何做到专注且不错过重要事情
    现代人每天要处理的事情繁多,如何能专注于当下,保持高效,又不错过重要事情?先说高效,如果你想着一小时后要给张三打个电话,下午两点半有个会,中午需要订高铁票,那么你就很难高度专注地投入手头的事情。反之,如果你高度专注,怎么保证各种事情到点时,你总能想起来?工作中有各种周期性的......
  • Flex筛子布局
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title>......