\(1 \leq n \leq 10^6\), 唯一分解(質因數分解) \(n!\),輸出 \(p_i,c_i\)。
階乘分解 AcWing197
思路
前置知識:線性篩 (質數判定的演算法4)。
顯然 \(n!\) 的每個質因子都小於等於 \(n\)。
因為 \(n! = n(n-1)(n-2)(n-3)\cdots 3 \cdot 2 \cdot 1\),所以質數 \(p\) 在 \(n!\) 出現的次數為 \(p\) 在 \(1\sim n\) 出現的次數。
對於 \(i=1,2,3\dots n\):
對於 \(p\):若有 \(p|i\),則 \(p\) 出現次數+1
對於 \(p^2\):若有 \(p^2|i\),則 \(p\) 出現次數 +1,而不是 +2,因為其中一個 \(p\) 在 \(p|i\) 時被統計了。
對於 \(p^3\):若有 \(p^3|i\),則 \(p\) 出現次數 +1,而不是 +3,因為其中一個 \(p\) 在 \(p|i\) 時被統計了,另一個 \(p\) 在 \(p^2|i\) 時被統計了。
...
則 \(p\) 在 \(n!\) 中出現的次數為 \(\lfloor\frac{n}{p}\rfloor + \lfloor\frac{n}{p^2}\rfloor + \lfloor\frac{n}{p^3}\rfloor + \cdots + \lfloor\frac{n}{p^{\lfloor\log_p{n}\rfloor}}\rfloor = \sum\limits_{p^k\leq n}{\lfloor\frac{n}{p^k}\rfloor}\)。
綜上有以下步驟:
- 線性篩求 \(1 \sim n\) 內的質數。\(O(n)\)
- 遍歷 \(1 \sim n\) 內的質數,找出質數\(p\),\(p|n\)。\(O(\pi(n))=O(\frac{n}{\log n})\)
- 對於質數 \(p\),求出在 \(n!\) 中出現的次數。\(O(\log n)\)
\(\pi(x)\) 是小於等於 \(x\) 的質數個數,約等於 \(\frac{n}{\log n}\)
綜上時間複雜度為 \(O(n + \frac{n}{\log n} \cdot \log n) = O(n)\)。
程式碼實現
int n;
long long v[N];
::std::vector<int> ps;
int main() {
scanf("%d", &n);
/* 線性篩 */
for(int i = 2; i <= n; i++)
{
if(!v[i])
v[i] = i, ps.push_back(i);
for(int j : ps)
if(v[i] < j || j > n / i) break;
else v[i * j] = j;
}
for(int i : ps)
{
ll p = i;
int c = 0;
while(p <= n)
{
c += n / p;
p *= i;
}
printf("%d %d\n", i, c);
}
return 0;
}