也許更好的閱讀體驗
\(\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;//當前這個數沒了
}
}