求1到n的質數個數和O(n)


也許更好的閱讀體驗
\(\mathcal{AIM}\)

我們知道:
對於一個合數\(x\)\(x=p^{a_1}_1*p^{a_2}_2*...*p^{a_n}_n\)
現在給出一個\(n\)\(x\in[1,n]\),所有\(x\)分解出的\(p\)的冪數和
例如
\(n=12\)
\(2=2^1\)
\(3=3^1\)
\(4=2^2\)
\(5=5^1\)
\(6=2^1*3^1\)
\(7=7^1\)
\(8=2^3\)
\(9=3^2\)
\(10=2^1*5^1\)
\(11=11^1\)
\(12=2^2*3^1\)

數字 個數
2 10
3 5
5 2
7 1
11 1

\(\mathcal{Resolvent}\)

對於一個合數\(x\)\(x=p^{a_1}_1*p^{a_2}_2*...*p^{a_n}_n\)

\(O(n\sqrt 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=1;j*j<=i&&j<=cnt;++j){
		int t=i;
		while (t%prime[j]==0)	++num[prime[j]],t/=prime[j];
	}

\(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)\)

對一個數 \(x\)
\(x/p_1\)顯然是比\(x\)小的,若我們知道\(x/p_1\)的答案,那么\(x\)的貢獻就是\(x/p_1\)的貢獻加上對\(p_1\)的一個貢獻
但我們把\(x/p_1\)的答案存下來只會增加復雜度
於是我們可以反過來循環,\(x\)先對\(p_1\)加一個貢獻,之后我們就可以認為多了一個\(x/p_1\)
計算\(x/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;//當前這個數沒了
	}
}



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM