Codeforces Round #643 (Div. 2) C(数论,思维,前缀和)

链接
Codeforces Round #643 (Div. 2) C(数论,思维,前缀和)_第1张图片

题意

给定四个数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
#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
}

你可能感兴趣的:(Codeforces Round #643 (Div. 2) C(数论,思维,前缀和))