虽然题目不难,但背后蕴含的考点还是很有意思的。

本题的核心考点是唯一分解定理

此考点曾在NOIP中涉及,非常重要!!!

例如 NOIP2009 Hankson的趣味题

唯一分解定理:设 pip_i 表示第 ii 个质数,那么对于任意正整数NN,都有唯一的一组 a1,a2,a3ana_1,a_2,a_3\dots a_n ,使得

N=p1a1×p2a2×p3a3××pnanN=p_1^{a_1}\times p_2^{a_2}\times p_3^{a_3}\times\dots\times p_n^{a_n}

其中 aia_i 可以等于00

用白话文说:任何数都可以表示为他的质因数们的若干次幂的乘积,而幂指数序列是确定的。

推论:对于 x,y\forall x,y ,其中

x=p1a1×p2a2×p3a3××pnanx=p_1^{a_1}\times p_2^{a_2}\times p_3^{a_3}\times\dots\times p_n^{a_n}

y=p1b1×p2b2×p3b3××pnbny=p_1^{b_1}\times p_2^{b_2}\times p_3^{b_3}\times\dots\times p_n^{b_n}

gcd(x,y)=p1min(a1,b1)×p2min(a2,b2)×p3min(a3,b3)××pnmin(an,bn)\gcd(x,y)=p_1^{\min(a_1,b_1)}\times p_2^{\min(a_2,b_2)}\times p_3^{\min(a_3,b_3)}\times\dots\times p_n^{\min(a_n,b_n)}

lcm(x,y)=p1max(a1,b1)×p2max(a2,b2)×p3max(a3,b3)××pnmax(an,bn)\operatorname{lcm}(x,y)=p_1^{\max(a_1,b_1)}\times p_2^{\max(a_2,b_2)}\times p_3^{\max(a_3,b_3)}\times\dots\times p_n^{\max(a_n,b_n)}

回到本题,给定整数 nn ,求有多少对 x,yx,y ,满足 lcm(x,y)=n\operatorname{lcm}(x,y)=n

nn 分解质因数,得到 nn 的唯一分解序列 S={a1,a2,a3,,an}S=\{a_1,a_2,a_3,\dots,a_n\}

对于序列中的每一个元素 aia_i ,要求 x,yx,y 的分解序列中的对应元素 xi,yix_i,y_i 更大的那个aia_i 相等,另一个可以在 [0,ai1][0,a_i-1] 中任取。

xi=aix_i=a_i 时, yi[0,ai1]y_i\in[0,a_i-1] ,共 aia_i 种方法;

yi=aiy_i=a_i 时, xi[0,ai1]x_i\in[0,a_i-1] ,共 aia_i 种方法。

根据加法原理,应有 di=2×aid_i=2\times a_i 种方法。

然而,刚刚的计算中, {xi=aiyi=ai\begin{cases}x_i=a_i\\y_i=a_i\end{cases} 的情况被算了两次,因此要减1。

对于分解序列中的其他元素,根据乘法原理,各个质因数直接的方法互不干涉,最终的答案应当是各 did_i 相乘的积

i=1ndi\prod_{i=1}^n d_i

最后是时间复杂度分析。

计算的瓶颈在于分解质因数,如果使用Pollard_Rho进行分解,时间复杂度为 O(n)O(\sqrt{\sqrt{n}}) ,非常小的一个数;然而如果用暴力分解质因数,时间复杂度为 O(n)O(\sqrt n) ,实际测试中可以通过本题。

实际上,在许多题目中,如果 nn 在longlong范围内且没有多组数据, O(n)O(\sqrt n) 的时间复杂度是很难TLE的。

所以本题就轻松愉快地解决啦!

总结:

  1. 唯一分解定理的内容及其推论,务必牢记

  2. 如果组成问题的各个“位”之间相互独立,可以考虑把待求解的问题“按位分解”,这种思想不仅在数论题中十分重要,在动态规划中也经常出现。

AC代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#define re register
typedef long long ll;
using namespace std;

ll n,cnt,ans = 1;

int main(){
	cin>>n;
	for(re int i = 2; i < sqrt(n); ++i){
		cnt = 0;
		while(n%i==0){
			++cnt;
			n /= i;
		}
		if(cnt) ans *= (cnt<<1)+1;
	}
	if(n>1) ans *= 3;//n>1
	cout<<ans<<endl;
	
	return 0;
}