早两天做了【枚举】无序三元组a*b*c问题加强版-CSDN博客,今天老师又给孩子们安排了这个无序三元组a*b*c问题加强版之2,K的最大值达到了10^12,按之前的双循环思路又过不了,看来只能用一个循环才能搞定。题目如下:
题面翻译
给出一个正整数 𝐾,问有多少三元组 (𝑎,𝑏,𝑐)满足 𝑎×𝑏×𝑐≤𝐾?
制約
- 1≤ 𝐾≤ 10^12
- 1≤ 𝑎,𝑏,𝑐 ≤ 𝐾
4个样例输入:2,10,31415,1000000000000
对应样例输出:4,53,1937281,402439152166882
经过仔细思考,我们可以找到用一个循环来解决的思路:
1)由于a,b,c可以任意交换位置,所以只要从1开始枚举a到小于等于a^3结束,分别计算出a*b*c≤k 且a≤b≤c的情况计数,再根组合方式直接计算出该方案的累计数。
比如K=10,我们可以这样分析:先计算最大的C值:maxC = k / a / b
(1)当a=1,b=1的情况,c可以取1-10,那么ans += (maxC - b + 1) * 3 - 2,减2就是排除c也为1时,只有一种组合,其它情况是3种组合;
(2)当a=1,b=2,c不能从1开始取,因为在第一步已经计算过了,只能取2-5,那么ans += (maxC - b + 1) * 6-3 ,减3时因为当c取2与b值相同时只有3种组合,而abc各不相同时有6种组合。
(3)当a=1的情况枚举完后,需要再枚举a++的情况。但这个a要到什么时候开始+1呢?按照上面分析思路,当maxC值小于b时就要加了,因为当maxC小于b的情况组合前面已经计算进来了。
(4)直到a*a*a>K时结算循环,但因题意K值最大为10^12,不能直接用a*a*a>K这个表达式,这样会超出long long数据范围,所以只能用k / a / a / a < 1来结束。
具体代码如下:
#include<bits/stdc++.h>
using namespace std;
int main() { //无序三元组a*b*c问题加强版 2
long long k, ans = 0;
cin >> k;
long long a = 1, b = 1;
while (1) { //只要循环到a^3<=K
long long maxC = k / a / b;
if (a == b) //ab相同时
ans += (maxC - b + 1) * 3 - 2;//abc相同时只有一种组合,其余是3种组合
else { //ab不同时
if (maxC < b) {
a++;
b = a - 1;
if (k / a / a / a < 1) break; //只要循环到a^3<=K,不能用a*a*a>k,超数据范围
} else if (maxC >= b) {
ans += (maxC - b + 1) * 6 - 3; //abc各不同时可组合6种,c选择与b相同时只有3种
}
}
b++;
}
cout << ans;
return 0;
}