求1到n的质数个数和O(n)

20 篇文章 0 订阅
17 篇文章 0 订阅

也许更好的阅读体验
A I M \mathcal{AIM} AIM

我们知道:
对于一个合数 x x x x = p 1 a 1 ∗ p 2 a 2 ∗ . . . ∗ p n a n x=p^{a_1}_1*p^{a_2}_2*...*p^{a_n}_n x=p1a1p2a2...pnan
现在给出一个 n n n x ∈ [ 1 , n ] x\in[1,n] x[1,n],所有 x x x分解出的 p p p的幂数和
例如
n = 12 n=12 n=12
2 = 2 1 2=2^1 2=21
3 = 3 1 3=3^1 3=31
4 = 2 2 4=2^2 4=22
5 = 5 1 5=5^1 5=51
6 = 2 1 ∗ 3 1 6=2^1*3^1 6=2131
7 = 7 1 7=7^1 7=71
8 = 2 3 8=2^3 8=23
9 = 3 2 9=3^2 9=32
10 = 2 1 ∗ 5 1 10=2^1*5^1 10=2151
11 = 1 1 1 11=11^1 11=111
12 = 2 2 ∗ 3 1 12=2^2*3^1 12=2231

数字个数
210
35
52
71
111

R e s o l v e n t \mathcal{Resolvent} Resolvent

对于一个合数 x x x x = p 1 a 1 ∗ p 2 a 2 ∗ . . . ∗ p n a n x=p^{a_1}_1*p^{a_2}_2*...*p^{a_n}_n x=p1a1p2a2...pnan

O ( n n ) O(n\sqrt n) O(nn )

这是最简单的想法,先记录哪些数是质数,再把 n n n以内所有的数分解掉

int cnt;
int prime[maxn],num[maxn];//prime -> 求出来的质数   num -> 每个数出现个数
bool vis[maxn];//欧拉筛里看其是否是质数
ols(n);//这是欧拉筛
for (int i=1;i<=n;++i)
	for (int j=;j*j<=i&&j<=cnt;++j){
		int t=i;
		while (t%prime[j]==0)	++num[prime[j]],t/=prime[j];
	}

O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

考虑可不可以直接对整体求
这个方法对一些其他题也很有用

int cnt;
int prime[maxn],num[maxn];
bool vis[maxn];
ols(n);
for (int i=1;i<=cnt;++i){
	int t=prime[i],mi=1;//mi -> mi次幂
	while (t<=n){
		num[prime[i]]+=n/t*mi;
		t*=prime[i],++mi;
	}
}

O ( n ) O(n) O(n)

对一个数 x x x
x / p 1 x/p_1 x/p1显然是比 x x x小的,若我们知道 x / p 1 x/p_1 x/p1的答案,那么 x x x的贡献就是 x / p 1 x/p_1 x/p1的贡献加上对 p 1 p_1 p1的一个贡献
但我们把 x / p 1 x/p_1 x/p1的答案存下来只会增加复杂度
于是我们可以反过来循环, x x x先对 p 1 p_1 p1加一个贡献,之后我们就可以认为多了一个 x / p 1 x/p_1 x/p1
计算 x / p 1 x/p_1 x/p1时答案就会多一,显然我们可以一直传递下去,这样每个数只用把自己最小质因子的贡献算出即可

int cnt;
int prime[maxn],num[maxn],come[maxn];//come[i] -> i的最小质因子
bool vis[maxn];
ols(n);
for (int i=n;i>=2;--i){
	if (vis[i]){//如果是个合数
		num[come[i]]+=num[i];//最小质因子加上当前这个数要计算次数
		num[i/come[i]]+=num[i];//加上这个数需计算次数
		num[i]=0;//当前这个数没了
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值