阶乘质因数分解

\(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;
}
posted @ 2024-11-01 22:31  kuailedetongnian  阅读(15)  评论(0编辑  收藏  举报