莫比乌斯反演
这里有个博客讲的很好:http://www.cnblogs.com/chenyang920/p/4811995.html
这里简要解释解释记录记录下笔记。
首先明确什么是莫比乌斯反演:
这里有一个函数,并有另一个函数,满足,那我们已知求的过程就是莫比乌斯反演。
具体公式为: 这里的可以理解成的系数,来控制的取值,具体可以看看上面的博客。
的具体求法可用线性筛实现。
当x可表示成偶数个质数相乘时,
当x可表示成奇数个质数相乘时,
其余情况则

1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #define N 10005 7 using namespace std; 8 bool visit[N]; 9 int n,u[N],prim[N],a,b,c,d,k,qwq,qaq,tot; 10 long long ans; 11 void pre(){ 12 memset(visit,false,sizeof(visit)); 13 tot=0; 14 u[1]=1; 15 for (int i=2;i<=N;i++){ 16 if (!visit[i]){ 17 visit[i]=true; 18 prim[++tot]=i; 19 u[i]=-1; 20 } 21 for (int j=1;j<=tot;j++){ 22 if (prim[j]*i>N) break; 23 visit[prim[j]*i]=true; 24 if (i%prim[j]) u[prim[j]*i]=-u[i]; 25 else break; 26 } 27 } 28 } 29 int main(){ 30 memset(u,0,sizeof(u)); 31 pre(); 32 scanf("%d",&n); 33 while (n--){ 34 ans=0; 35 scanf("%d%d%d",&a,&b,&k); 36 if (a>b) swap(a,b); 37 qwq=a/k; qaq=b/k; 38 for (int i=1;i<=qwq;i++) 39 ans+=(long long)u[i]*(long long)(qwq/i)*(long long)(qaq/i); 40 printf("%lld\n",ans); 41 } 42 return 0; 43 }
这里有部分例题的讲解:http://sxysxy.org/blogs/77
莫比乌斯反演的题目有的需要分块求解答案,前缀和维护,因为考虑到整除的性质,即(i~i+p-1)整除p答案都是一样的,我们可以直接计算这部分的答案。
具体可参考洛谷上的一题:https://www.luogu.org/problem/show?pid=2522

1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #pragma GCC optamize("O3") 6 #pragma G++ optamize("O3") 7 #include<cmath> 8 #define N 50005 9 using namespace std; 10 bool visit[N]; 11 int n,u[N],prim[N],a,b,c,d,k,qwq,qaq,qoq,qvq,tot,sum[N]; 12 long long ans; 13 void pre(){ 14 tot=0; 15 sum[1]=1; 16 u[1]=1; 17 for (int i=2;i<=N;i++){ 18 if (!visit[i]){ 19 prim[++tot]=i; 20 u[i]=-1; 21 } 22 for (int j=1;j<=tot&&prim[j]*i<=N;j++){ 23 visit[prim[j]*i]=true; 24 if (i%prim[j]) u[prim[j]*i]=-u[i]; 25 else break; 26 } 27 sum[i]=sum[i-1]+u[i]; 28 } 29 } 30 long long cale(int l,int r){ 31 long long tmp=0; 32 if (l>r) swap(l,r); 33 for (int i=1,go=0;i<=l;i=go+1){ 34 go=min(l/(l/i),r/(r/i)); //从i开始最长的相等区间长度为min(l / (l / i),r / (r / i)),比如l / (l / i),设l / i = p,p表示整除时的值,那么l / p就是从i开始整除值为p的个数了 35 tmp+=(l/i)*(r/i)*(sum[go]-sum[i-1]); 36 } 37 return tmp; 38 } 39 int main(){ 40 pre(); 41 scanf("%d",&n); 42 while (n--){ 43 ans=0; 44 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 45 qwq=b/k;qaq=(a-1)/k;qoq=d/k;qvq=(c-1)/k; 46 for (int i=1;i<=qwq-qaq;i++) 47 ans=cale(qwq,qoq)-cale(qwq,qvq)-cale(qaq,qoq)+cale(qaq,qvq); //根据容斥原理 48 printf("%lld\n",ans); 49 } 50 return 0; 51 }
但似乎还是会超时......(或许常数过大QAQ)
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/7352846.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步