P4213 【模板】杜教筛(Sum)

题目链接

P4213 【模板】杜教筛(Sum)

题目描述

给定一个正整数,求

ans1=i=1nφ(i)

ans2=i=1nμ(i)

输入格式

本题单测试点内有多组数据

输入的第一行为一个整数,表示数据组数 T

接下来 T 行,每行一个整数 n,表示一组询问。

输出格式

对于每组询问,输出一行两个整数,分别代表 ans1ans2

样例 #1

样例输入 #1

6 1 2 8 13 30 2333

样例输出 #1

1 1 2 0 22 -2 58 -3 278 -3 1655470 2

提示

数据规模与约定

对于全部的测试点,保证 1T101n<231

解题思路

杜教筛

杜教筛主要用来快速求解数论函数的前缀和问题,即对于这样一个数论函数 f(x),计算 S(n)=i=1nf(i)

设任意两个积性函数 f(x),g(x),由迪利克雷卷积,设 h(x)=f·g(x),则 i=1nh(i)=i=1nf·g(x)=i=1nd|iig(d)f(id)=d=1ng(d)d|inf(id)=d=1ng(d)i=1ndf(i)=d=1nS(nd),则可以得到杜教筛公式:

g(1)S(n)=i=1nh(i)i=2ng(i)S(ni)

线性预处理前 O(n23) 个数,其复杂度为:

  • 时间复杂度:O(n23)

否则:

  • 时间复杂度:O(n34)

考虑本题:求解莫比乌斯前缀和,考虑元函数 ϵ 作为迪利克雷卷积,由莫比乌斯函数的性质 d|xμ(d)={ 1,x=1 0,x1=ϵ(x),即 ϵ=μ·1,则 S(n)=1i=1nS(ni),此即莫比乌斯前缀和

求解欧拉函数前缀和,由欧拉函数性质:d|nϕ(d)=n,同样地,令 h(x)=ϕ(x)·1,则 S(n)=i=1nϕ(i)i=2nS(ni)=n×(n+1)2i=2nS(ni),此即欧拉函数的前缀和

  • 时间复杂度:O(n23)

代码

// Problem: P4213 【模板】杜教筛(Sum) // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P4213 // Memory Limit: 512 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> // #define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1e6+5; int t,n,cnt,prime[N],v[N],u[N]; LL phi[N]; unordered_map<LL,int> mp_u; unordered_map<int,LL> mp_phi; void init(int n) { u[1]=phi[1]=1; for(int i=2;i<=n;i++) { if(!v[i]) { u[i]=-1; prime[++cnt]=v[i]=i; phi[i]=i-1; } for(int j=1;j<=cnt&&i*prime[j]<=n;j++) { if(v[i]<prime[j])break; if(i%prime[j]==0)u[i*prime[j]]=0; else u[i*prime[j]]=-u[i]; v[i*prime[j]]=prime[j]; phi[i*prime[j]]=(LL)phi[i]*(i%prime[j]?prime[j]-1:prime[j]); } } for(int i=1;i<=n;i++)u[i]+=u[i-1],phi[i]+=phi[i-1]; } LL get(int a,LL b) { return a/(a/b); } int ask_u(int x) { if(x<N)return u[x]; if(mp_u[x])return mp_u[x]; int res=1; for(LL i=2,j;i<=x;i=j+1) { j=get(x,i); res-=(LL)ask_u(x/i)*(j-i+1); } return mp_u[x]=res; } LL ask_phi(LL x) { if(x<N)return phi[x]; if(mp_phi[x])return mp_phi[x]; LL res=x*(x+1)/2; for(LL i=2,j;i<=x;i=j+1) { j=get(x,i); res-=ask_phi(x/i)*(j-i+1); } return mp_phi[x]=res; } int main() { init(N-1); for(scanf("%d",&t);t;t--) { scanf("%d",&n); printf("%lld %d\n",ask_phi(n),ask_u(n)); } return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16837323.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示