【题解】AT_abc292_c 题解

AT_abc292_c 题解

思路分析

一道挺不错的思维题。

首先,题目要求求出满足 A×B+C×D=NA \times B+ C \times D = N 的四元组 (A,B,C,D)(A,B,C,D),且顺序不同,数相同的不算同一种。于是,我们可以先枚举 A×BA \times BC×DC \times D 的值,随后我们就可以通过分解因数对的方式枚举出 (A,B)(A,B)(C,D)(C,D) 各有多少组(计顺序)。最后根据乘法原理,将两者统计出来的结果相乘即可。

那么其次,如何通过分解因数对的方式枚举出 (A,B)(A,B)(C,D)(C,D) 各有多少组(计顺序)呢?我们以 (A,B)(A,B) 为例。可以发现,由于两者乘积固定且已知,如果设其为 kk。则 (A,B)(A,B) 可以表示为 (A,kA)(A,\dfrac{k}{A}),也就是确定了 AA 就确定了整个组 (A,B)(A,B) 。由于又有 AkA \mid k,即 AAkk 的因数,因数与整个组 (A,B)(A,B) 一一对应。也就是说,乘积有多少个因数个数,就有有多少组(计顺序)。

然后就是实现了。题解区中的大佬们都是用 O(NN)O(N \sqrt{N}) 的算法直接在程序中来预处理因数个数的。事实上,这样子并不稳健,因为如果不加任何优化的话,2×1052 \times 10^5 的范围中很可能会被卡常。所以我认为最好直接打表处理出来范围中所有数的因数个数,这样子就可以实现在 O(N)O(N) 的复杂度内计算出正确结果。

代码

打表代码:

for(int i = 1;i <= 200000;i++) //遍历每个数
{
	int cnt = 0; //因数个数计数器
	for(int j = 1;j * j <= i;j++) //遍历每个因数
	{
		if(i % j == 0) //如果能被整除
		{
			cnt += 2; //加入两个因数
		}
		if(j * j == i) //如果是平方数
		{
			cnt--; //要进行去重
		}
	}
	cout << cnt << ",";
}

计算结果部分关键代码:

long long kkk = 0; //总结果计数器
for(int i = 1;i <= n;i++) //枚举AB乘积
{
	int j = n - i; //由 AB+CD=N,CD=N-AB 得来。
	kkk += (ys[i] * ys[j]); //根据乘法原理计算结果
}
cout << kkk << endl;
posted @ 2023-03-06 22:43  邻补角-SSA  阅读(14)  评论(0)    收藏  举报  来源