【51Nod 1244】莫比乌斯函数之和
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1244
模板题。。。
杜教筛和基于质因子分解的筛法都写了一下模板。
杜教筛
用杜教筛求积性函数\(f(n)\)的前缀和\(S(n)=\sum\limits_{i=1}^nf(i)\),需要构造一个\(g(n)\)使得\(\sum\limits_{d|n}f(d)g\left(\frac nd\right)\)和\(\sum\limits_{i=1}^ng(i)\)都可以快速求出。因为我们有公式:
\]
对于\(\mu(n)\)的前缀和,很明显\(g(n)=1\)。这样的话:
\]
\]
用Hash表存储S的值
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 1E10;
const int UP = 3981071;
int mu[UP + 3], prime[UP + 3], num = 0, sum[UP + 3];
bool notp[UP + 3];
void Euler_shai() {
sum[1] = 1;
for (int i = 2; i <= UP; ++i) {
if (!notp[i]) {
prime[++num] = i;
mu[i] = -1;
}
for (int j = 1, pro; j <= num && (pro = prime[j] * i) <= UP; ++j) {
notp[pro] = true;
if (i % prime[j] == 0) {
mu[pro] = 0;
break;
} else
mu[pro] = -mu[i];
}
sum[i] = sum[i - 1] + mu[i];
}
}
struct HashTable {
static const int p = 1000007;
ll val[p], ref[p];
HashTable() {memset(ref, -1, sizeof(ref));}
void add(ll pos, ll nu) {
int tmp = (int) (pos % p);
while (ref[tmp] != -1) {
if (ref[tmp] == pos) return;
++tmp; if (tmp == p) tmp = 0;
}
ref[tmp] = pos;
val[tmp] = nu;
}
ll query(ll pos) {
int tmp = (int) (pos % p);
while (ref[tmp] != pos) {++tmp; if (tmp == p) tmp = 0;}
return val[tmp];
}
} HT;
ll Sum(ll x) {
return x <= UP ? sum[x] : HT.query(x);
}
void DJ_shai(ll n) {
for (ll i = n, y; i >= 1; i = n / (y + 1)) {
y = n / i;
if (y <= UP) continue;
ll ret = 0;
for (ll j = 2, l, pre = 1; j <= y; ++j) {
l = y / j;
j = y / l;
ret += Sum(l) * (j - pre);
pre = j;
}
HT.add(y, 1ll - ret);
}
}
int main() {
Euler_shai();
ll a, b;
scanf("%lld%lld", &a, &b);
DJ_shai(b);
DJ_shai(a - 1);
printf("%lld\n", Sum(b) - Sum(a - 1));
return 0;
}
基于质因子分解的筛法
基于质因子分解的筛法细节比较多(貌似被称作洲哥筛?)。
\]
设小于等于\(\sqrt n\)的质数从小到大排列为\(p_1,p_2\dots p_m\)。
设\(g(i,j)\)表示\([1,j]\)内与前i个质数互质的数的个数。
转移:\(g(i,j)=g(i-1,j)-g\left(i-1,\left\lfloor\frac j{p_i}\right\rfloor\right)\)
\(g(m,j)-1\)即为\([1,j]\)内大于\(\sqrt n\)的质数个数,它的相反数就是\(\sum\limits_{\sqrt n<p\leq j且p为质数}\mu(p)\)
枚举小于\(\sqrt n\)的所有数的\(\mu\),并和上面等式右边的括号内的数相乘求和。
这样剩下的就是大于等于\(\sqrt n\)的满足条件的\(\mu\)值,这些\(\mu\)值也要乘上括号内的数,不过这些括号内的数都是1,所以大于等于\(\sqrt n\)的满足条件的\(\mu\)值就可以统一计算了。
把\(p_1,p_2\dots p_m\)翻转,变成从大到小。
再设\(f(i,j)\)表示用前i个质数构成质因子的数中在\([1,j]\)内的数的\(\mu\)值和。
转移:\(f(i,j)=f(i-1,j)+\mu(p_i)f\left(i-1,\left\lfloor\frac j{p_i}\right\rfloor\right)\)
\(f(m,n)-\sum\limits_{1\leq i<\sqrt n}\mu(i)\)就是统一计算出来的和。
因为下取整只有\(O(\sqrt n)\)种取值,枚举小于等于\(\sqrt n\)的质数,质数个数大概是\(\frac{\sqrt n}{\log\sqrt n}\),所以时间复杂度是\(O\left(\frac n{\log n}\right)\)。
加上一些优化就可以达到\(O\left(\frac{n^{\frac 34}}{\log n}\right)\)。
这只是筛最简单的\(\mu\)的前缀和,更一般的积性函数的前缀和求法以及优化到\(O\left(\frac{n^{\frac 34}}{\log n}\right)\)的方法详见2016年候选人论文《积性函数求和的几种方法》,这里实在说不下了。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1E10;
const int UP = 1E5;
bool notp[UP + 3];
int prime[UP + 3], sum_p[UP + 3], sum_mu[UP + 3], mu[UP + 3], pre[UP * 2 + 3], num = 0;
ll G[UP * 2 + 3], F[UP * 2 + 3], J[UP * 2 + 3];
void Euler_shai(int n) {
mu[1] = sum_mu[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!notp[i]) {
prime[++num] = i;
mu[i] = -1;
sum_p[i] = sum_p[i - 1] + 1;
} else
sum_p[i] = sum_p[i - 1];
for (int j = 1, pro; j <= num && (pro = i * prime[j]) <= n; ++j) {
notp[pro] = true;
if (i % prime[j] == 0) break;
else mu[pro] = -mu[i];
}
sum_mu[i] = sum_mu[i - 1] + mu[i];
}
}
struct HashTable {
static const int ppp = 2333333;
ll ref[ppp]; int val[ppp];
void clr() {memset(ref, -1, sizeof(ref)); ref[0] = val[0] = 0;}
void add(ll pos, int nu) {
int tmp = pos % ppp;
while (ref[tmp] != -1) {++tmp; if (tmp == ppp) tmp = 0;}
ref[tmp] = pos; val[tmp] = nu;
}
int query(ll pos) {
int tmp = pos % ppp;
while (ref[tmp] != pos) {++tmp; if (tmp == ppp) tmp = 0;}
return val[tmp];
}
} HT;
ll ZY_shai(ll n) {
int cnt = 0, sqf = floor(sqrt(n)), sqc = ceil(sqrt(n));
while (prime[num] > sqf) --num;
HT.clr();
for (ll i = n, y; i >= 1; i = n / (y + 1)) {
J[++cnt] = (y = n / i);
HT.add(y, cnt);
G[cnt] = y;
pre[cnt] = 0;
}
ll pp, delta;
for (int i = 1, p = prime[i]; i <= num; p = prime[++i]) {
pp = 1ll * p * p;
for (int j = cnt; j >= 1 && J[j] >= pp; --j) {
int id = HT.query(J[j] / p);
delta = max(G[id] - (i - 1 - pre[id]), 1ll);
G[j] -= delta;
pre[j] = i;
}
}
for (int j = cnt; j >= 1; --j)
G[j] = max(G[j] - (num - pre[j]), 1ll);
ll ans = 0;
for (int i = 1; i < sqc; ++i)
ans += (2ll - G[HT.query(n / i)]) * mu[i];
ll prep = 0;
for (int j = 1; j <= cnt; ++j) F[j] = 1;
for (int i = num, p = prime[i]; i >= 1; p = prime[--i]) {
pp = 1ll * p * p;
for (int j = cnt; j >= 1 && J[j] >= pp; --j) {
if (J[j] < prep * prep) {
if (J[j] > prep) F[j] = 1 - (sum_p[min(J[j], 1ll * sqf)] - sum_p[prep - 1]);
else F[j] = 1;
}
int id = HT.query(J[j] / p);
if (J[id] < prep * prep) {
if (J[id] >= prep) delta = 1 - (sum_p[min(J[id], 1ll * sqf)] - sum_p[prep - 1]);
else delta = 1;
} else
delta = F[id];
F[j] -= delta;
}
prep = p;
}
return ans + F[cnt] - sum_mu[sqc - 1];
}
int main() {
ll a, b;
scanf("%lld%lld", &a, &b);
Euler_shai((int) sqrt(b));
b = ZY_shai(b);
a = ZY_shai(a - 1);
printf("%lld\n", b - a);
return 0;
}
总结
杜教筛比质因子分解筛法要快。质因子分解筛法可以筛更加一般的积性函数,比杜教筛无脑,但细节巨多,代码量大(容易写残)。
总算写完了
【51Nod 1244】莫比乌斯函数之和的更多相关文章
- 51nod 1244 莫比乌斯函数之和
题目链接:51nod 1244 莫比乌斯函数之和 题解参考syh学长的博客:http://www.cnblogs.com/AOQNRMGYXLMV/p/4932537.html %%% 关于这一类求积 ...
- 51nod 1244 莫比乌斯函数之和 【杜教筛】
51nod 1244 莫比乌斯函数之和 莫比乌斯函数,由德国数学家和天文学家莫比乌斯提出.梅滕斯(Mertens)首先使用μ(n)(miu(n))作为莫比乌斯函数的记号.具体定义如下: 如果一个数包含 ...
- [51Nod 1244] - 莫比乌斯函数之和 & [51Nod 1239] - 欧拉函数之和 (杜教筛板题)
[51Nod 1244] - 莫比乌斯函数之和 求∑i=1Nμ(i)\sum_{i=1}^Nμ(i)∑i=1Nμ(i) 开推 ∑d∣nμ(d)=[n==1]\sum_{d|n}\mu(d)=[n== ...
- 51nod 1244 莫比乌斯函数之和(杜教筛)
[题目链接] http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1244 [题目大意] 计算莫比乌斯函数的区段和 [题解] 利 ...
- 51Nod.1244.莫比乌斯函数之和(杜教筛)
题目链接 map: //杜教筛 #include<map> #include<cstdio> typedef long long LL; const int N=5e6; in ...
- 51nod 1244 莫比乌斯函数之和 【莫比乌斯函数+杜教筛】
和bzoj 3944比较像,但是时间卡的更死 设\( f(n)=\sum_{d|n}\mu(d) g(n)=\sum_{i=1}^{n}f(i) s(n)=\sum_{i=1}^{n}\mu(i) \ ...
- 51 NOD 1244 莫比乌斯函数之和(杜教筛)
1244 莫比乌斯函数之和 基准时间限制:3 秒 空间限制:131072 KB 分值: 320 难度:7级算法题 收藏 关注 莫比乌斯函数,由德国数学家和天文学家莫比乌斯提出.梅滕斯(Mertens) ...
- 【51nod】1244 莫比乌斯函数之和
题解 求积性函数的前缀和?杜教筛! 这不给一发杜教筛入门必备之博客= = https://blog.csdn.net/skywalkert/article/details/50500009 好了,然后 ...
- 51nod1244 莫比乌斯函数之和
推公式.f[n]=1-∑f[n/i](i=2...n).然后递归+记忆化搜索.yyl说这叫杜教筛?时间复杂度貌似是O(n 2/3)的? #include<cstdio> #include& ...
- 51nod 1240 莫比乌斯函数
题目链接:51nod 1240 莫比乌斯函数 莫比乌斯函数学习参考博客:http://www.cnblogs.com/Milkor/p/4464515.html #include<cstdio& ...
随机推荐
- ITTC数据挖掘系统(六)批量任务,数据查看器和自由文档
这一次带来了一系列新特新,同时我们将会从商业智能的角度讨论软件的需求 一. 批量任务向导 一个常用的需求是完成处理多个任务,可能是同一个需求以不同的参数完成多次,这类似批量分析某一问题:或者是不同的需 ...
- c#编程基础之枚举
枚举的意义就在于限制变量取值范围. 当可以确定的几种取值时才可以用. 如果输入一个字符串需要进行判断是否是我们需要的字符串时,则一般需要这样写: using System; using System. ...
- 【移动端兼容问题研究】javascript事件机制详解(涉及移动兼容)
前言 这篇博客有点长,如果你是高手请您读一读,能对其中的一些误点提出来,以免我误人子弟,并且帮助我提高 如果你是javascript菜鸟,建议您好好读一读,真的理解下来会有不一样的收获 在下才疏学浅, ...
- 一个由Response.Redirect 引起的性能问题的分析
现象: 某系统通过单点登录(SSO) 技术验证用户登录.用户在SSO 系统上通过验证后,跳转到某系统的主页上面.而跳转的时间很长,约1分钟以上. 分析步骤: 在问题复现时抓取Hang dump 进行分 ...
- Moon.Orm 入门总指南
注意:下面的pdf文件强烈建议下载或在线查看 1)旗舰版帮助文档点击查看或下载 2)http://pan.baidu.com/s/1hq7krFu(新手手册下载)(强烈推荐) 3)性能及规范下载,网友 ...
- ASP.NET Core 整合Autofac和Castle实现自动AOP拦截
前言: 除了ASP.NETCore自带的IOC容器外,我们还可以使用其他成熟的DI框架,如Autofac,StructureMap等(笔者只用过Unity,Ninject和Castle). 1.ASP ...
- Maven环境配置
1.下载Maven: 下载地址:http://maven.apache.org/ 2..安装 Maven 如果需要使用到 Maven ,必须首先安装 Maven , Maven 的下载地址在 Apac ...
- c语言实现输入一组数自动从大到小排列
#include <stdio.h>main(){ int x; printf("请输入要排序数字个数:"); scanf("%d" ...
- Effective java笔记(一),创建与销毁对象
1.考虑用静态工厂方法代替构造器 类的一个实例,通常使用类的公有的构造方法获取.也可以为类提供一个公有的静态工厂方法(不是设计模式中的工厂模式)来返回类的一个实例.例如: //将boolean类型转换 ...
- linux(八)__yum工具
自动处理依赖性关系,并且一次安装所有依赖的软体包,无须繁琐地一次次下载.安装. 什么是yum? yum工具实例: 因为yum指定的软件仓库源是国外的网站,在国内访问较慢.我们更改它的仓库源. 首先先备 ...