欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-01 17:47:14
...

AIM\mathcal{AIM}

我们知道:
对于一个合数xxx=p1a1p2a2...pnanx=p^{a_1}_1*p^{a_2}_2*...*p^{a_n}_n
现在给出一个nnx[1,n]x\in[1,n],所有xx分解出的pp的幂数和
例如
n=12n=12
2=212=2^1
3=313=3^1
4=224=2^2
5=515=5^1
6=21316=2^1*3^1
7=717=7^1
8=238=2^3
9=329=3^2
10=215110=2^1*5^1
11=11111=11^1
12=223112=2^2*3^1

数字 个数
2 10
3 5
5 2
7 1
11 1

Resolvent\mathcal{Resolvent}

对于一个合数xxx=p1a1p2a2...pnanx=p^{a_1}_1*p^{a_2}_2*...*p^{a_n}_n

O(nn)O(n\sqrt n)

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

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(nlog2n)O(nlog_2n)

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

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)

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

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;//当前这个数没了
	}
}