mobius反演讲解
2014-01-08 18:13
288 查看
mobius反演的基本形式为,假设知道函数F(x)=Σf(d) d|x,那么我们可以推出f(x)=Σmiu(d)*F(x/d) d|x,另一基本形式为假设知道函数F(x)=Σf(d) x|d,那么我们可以推出f(x)=Σmiu(d)*F(d/x) x|d,第二种形式可以由容斥定理得出,在此不再赘述。
我们由一个例子来了解mobius反演的作用。
求解ans=Σ(0<i<=n)Σ(0<j<=m)1(gcd(i,j)=1)即n,m范围中互质点对儿数。
我们设 F(x)为gcd(i,j)|x的点对儿数量,f(x)为gcd(i,j)=x的点对儿数量。那么易得F(x)=Σf(d) x|d,那么由第二形式可得f(x)=Σmiu(d)*F(d/x) x|d,那么这道题就是求f(1),即f(1)=Σmiu(d)*F(d) d<=min(n,m),比较显然的是F(x)=floor(n/d)*floor(m/d)。那么我们可以得到答案的形式
ans=Σmiu(i)*floor(n/i)*floor(m/i)。可以O(n)的求解。
但是对于某些问题,O(n)是无法在规定时间内完成的,我们考虑w=floor(n/i)*floor(m/i),对于i递增,w为不减的,即存在连续段w值相同。那么我们可以求出mobius函数的前缀和,然后分块的来求解,我们找到w值相同的区间,即存在j,满足floor(n/j)=floor(n/i),floor(m/j)=floor(m/i),那么j=min(floor(n/floor(n/i)),floor(m/floor(m/i))),这样对于w相同的块儿一起处理就行了,这样时间复杂度就变成了O(sqrt(n))。
基础题bzoj 2301 http://61.187.179.132/JudgeOnline/problem.php?id=2301
这道题就是多了一个容斥定理求解,基本的思路和上面的相同,可以作为练手题。
我们由一个例子来了解mobius反演的作用。
求解ans=Σ(0<i<=n)Σ(0<j<=m)1(gcd(i,j)=1)即n,m范围中互质点对儿数。
我们设 F(x)为gcd(i,j)|x的点对儿数量,f(x)为gcd(i,j)=x的点对儿数量。那么易得F(x)=Σf(d) x|d,那么由第二形式可得f(x)=Σmiu(d)*F(d/x) x|d,那么这道题就是求f(1),即f(1)=Σmiu(d)*F(d) d<=min(n,m),比较显然的是F(x)=floor(n/d)*floor(m/d)。那么我们可以得到答案的形式
ans=Σmiu(i)*floor(n/i)*floor(m/i)。可以O(n)的求解。
但是对于某些问题,O(n)是无法在规定时间内完成的,我们考虑w=floor(n/i)*floor(m/i),对于i递增,w为不减的,即存在连续段w值相同。那么我们可以求出mobius函数的前缀和,然后分块的来求解,我们找到w值相同的区间,即存在j,满足floor(n/j)=floor(n/i),floor(m/j)=floor(m/i),那么j=min(floor(n/floor(n/i)),floor(m/floor(m/i))),这样对于w相同的块儿一起处理就行了,这样时间复杂度就变成了O(sqrt(n))。
基础题bzoj 2301 http://61.187.179.132/JudgeOnline/problem.php?id=2301
这道题就是多了一个容斥定理求解,基本的思路和上面的相同,可以作为练手题。
/************************************************************** Problem: 2301 User: BLADEVIL Language: Pascal Result: Accepted Time:34964 ms Memory:1204 kb ****************************************************************/ //By BLADEVIL var a, b, c, d, k, t :longint; ans :int64; i :longint; prime, miu, mindiv :array[0..50010] of longint; sum :array[0..50010] of int64; procedure make; var i, j :longint; begin miu[1]:=1; for i:=2 to 50000 do begin if mindiv[i]=0 then begin inc(prime[0]); prime[prime[0]]:=i; mindiv[i]:=i; miu[i]:=-1; end; for j:=1 to prime[0] do begin if i*prime[j]>50000 then break; mindiv[i*prime[j]]:=prime[j]; if i mod prime[j]=0 then begin miu[i*prime[j]]:=0; break; end else miu[i*prime[j]]:=-miu[i]; end; end; for i:=1 to 50000 do sum[i]:=sum[i-1]+miu[i]; end; function calc(n,m:longint):longint; var t, t1, t2 :int64; i :longint; xx :int64; begin calc:=0; i:=1; if n>m then xx:=m else xx:=n; while i<=xx do begin t1:=n div (n div i); t2:=m div (m div i); if t1<t2 then t:=t1 else t:=t2; calc:=calc+(sum[t]-sum[i-1])*(n div i)*(m div i); i:=t+1; end; end; begin make; readln(t); for i:=1 to t do begin readln(a,b,c,d,k); ans:=int64(calc(b div k,d div k)) -int64(calc((c-1) div k,b div k)) -int64(calc((a-1) div k,d div k)) +int64(calc((a-1) div k,(c-1) div k)); writeln(ans); end; end.
相关文章推荐
- Linux vi/vim替换命令的使用说明[转]
- 如何突破职场瓶颈
- c++类的构造函数
- SPDY 是什么?如何部署 SPDY?
- mysql 插入数据失败防止自增长主键增长的方法
- EXT JS 学习
- c++的参数传递
- c++的this指针
- HA高可用集群服务搭建
- linux 下使用 rsync 进行文件 同步
- c++的const详解
- poj 3187 Backward Digit Sums
- 安装交叉编译工具,执行arm-linux-gcc –v命令出现提示找不到该文件或目录?解决方法
- 迭代器
- 软件架构师之路
- c++的vector容器
- 从问题看本质: 研究TCP close_wait的内幕
- nginx https 测试 及status模块
- Box model小心得
- jQuery之easyUi