题意
给定四个数A B C D (A<=B<=C<=D<=5e5),创造三条边a (A<=a<=B),b(B<=b<=C),c(C<=c<=D),使这三条边可以组成一个三角形,求满足条件的总方案数。
思路
- 形成三角形的条件是 a + b > c, 逐个枚举 a 和 b 将会超时
- 我们先可以利用差分数组来预处理 a + b 的个数得到数组S[]。
- 然后用前缀和得出 a + b 的个数,数组S[]前缀相加即可得到,此时S[i] 表示 a和b 满足 a + b = i 的情况总数。
- 接下来枚举c(C <= c <= D)求出总方案数,对于每个 c ,ans += S[c + 1] + ~ ~ ~ + S[B+C] ,但是S[c + 1] + ~ ~ ~ + S[B+C] 的处理多了一层循环,所以我们得在这之前再使用一次前缀和,使得S[c + 1] + ~ ~ ~ + S[B+C] = S[B+C] - S[c]。
- 枚举 c ,ans += S[B+C] - S[c]
- 输出ans
- 举例:给出数据2 4 6 7,差分数组处理将得到:S[0 ~ 5] = 0,S[6 ~ 8] = 1, S[9 ~ 11] = -1 。然后前缀和处理得到:
S[0 ~ 5] = 0, S[6] = 1, S[7] = 2, S[8] = 3, S[9] = 2,S[10] = 1,S[11] = 0。现在,S[i] 表示 a b 满足 a + b = i 的情况总数,再进行前缀和 S[0~5] = 0, S[6] = 1, S[7] = 3, S[8] = 6, S[9] = 8, S[10] = 9, S[11] = 9。枚举c = 6,7:ans = ans + S[10] - S[6] = 8, ans = ans + S[10] - S[7] = 8 + 6 = 14。输出14
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
int A,B,C,D,a[N];
signed main()
{
cin >> A >> B >> C >> D;
for (int i = A; i <= B; i++){ // 差分数组
a[B + i]++;
a[C + i + 1]--;
}
for (int i = 1; i < N; i++)
a[i] += a[i - 1]; // 边长 a + b 的所有可能情况
for (int i = 1; i < N; i++)
a[i] += a[i - 1]; // 前面S[]数组的汇总
int ans = 0;
for (int i = C; i <= D; i++)
ans += a[B + C] - a[i]; // 求出答案,当 B+C 小于 i 时,此时 i 明显已经不可能形成三角形,如果前面的循
cout << ans << "\n"; // 环不循环到N,a[B + C] - a[i] 就不会等于0, 得到错误的答案。所以前缀和的
return 0; // 循环才会枚举1~N。更直接点我们可以当i > B+C时,直接break
}