思路分析
深度优先搜索(DFS)思路
- 定义与参数说明
dfs
函数中,last
记录上一条边的长度,用于保证新选边长度大于上一条边,实现三边互不相等 。cnt
记录已选边的数量,当cnt
达到3
时,就构成了一个三角形。sum
是已选边的长度总和,mul
是已选边长度的乘积。pre
数组是前缀和数组,pre[i]
表示值小于等于i
的三角形的数量。
- 递归过程
- 从
last + 1
开始枚举新边长度i
。若i * mul > 1000000
,说明后续乘积会超出范围,直接返回,不再继续搜索。 - 当
cnt == 2
时,若sum <= i
,不满足三角形任意两边之和大于第三边的条件,返回。 - 满足条件则递归调用
dfs
,更新参数继续寻找下一条边 。当cnt == 3
时,说明构成了一个三边互不相等的三角形,将pre[mul]
加1
。
- 从
- 前缀和处理与查询
- DFS 完成后,通过遍历让
pre[i] += pre[i - 1]
,构建前缀和数组。 - 对于每个询问区间
[l, r]
,利用前缀和pre[r] - pre[l - 1]
快速得到值在该区间内的三角形数量。
- DFS 完成后,通过遍历让
枚举思路
- 三层循环枚举三边
- 最外层循环枚举最短边
i
,限定条件i * i * i < N
,因为当三边相等且为i
时,乘积为i * i * i
,超过N
就没必要枚举了。 - 中间层循环枚举次长边
j
,限定条件i * j * j < N
,保证三边乘积不超范围,且j > i
确保三边不等。 - 最内层循环枚举最长边
k
,条件i * j * k < N
保证乘积不超范围,k < i + j
满足三角形三边关系。在满足条件时,将a[i * j * k]
加1
,a
数组记录值为i * j * k
的三角形出现次数。
- 最外层循环枚举最短边
- 前缀和处理与查询
- 遍历让
pre[i] = pre[i - 1] + a[i]
,构建前缀和数组。 - 对于每个询问区间
[l, r]
,同样利用前缀和pre[r] - pre[l - 1]
计算值在该区间内的三角形数量。
- 遍历让
dfs代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,pre[1000005];
void dfs(int last,int cnt,int sum,int mul){
if(cnt==3){
pre[mul]++;
return;
}
for(int i=last+1;i<=1000000;++i){
if(i*mul>1000000)return;
if(cnt==2&&sum<=i)return;
dfs(i,cnt+1,sum+i,i*mul);
}
}
signed main()
{
cin>>n;
dfs(0,0,0,1);
for(int i=1;i<=1000000;++i){
pre[i]+=pre[i-1];
}
while(n--){
int l,r;
cin>>l>>r;
cout<<pre[r]-pre[l-1]<<'\n';
}
return 0;
}
枚举代码:
#include<iostream>
using namespace std;
int a[1000005],pre[1000005],n;
const int N=1e6+1;
int main(){
cin>>n;
for(int i=1;i*i*i<N;i++)
{
for(int j=i+1;i*j*j<N;j++)
{
for(int k=j+1;i*j*k<N&&k<i+j;k++)
{
a[i*j*k]++;
}
}
}
for(int i=1;i<=N;i++)
{
pre[i]=pre[i-1]+a[i];
}
while(n--)
{
int l,r;
cin>>l>>r;
cout<<pre[r]-pre[l-1]<<'\n';
}
return 0;
}