P3799 妖梦拼木棒

题目链接:

欲由4根木棒组成一个正三角形,则必有2根长度相等,且另外2根长度之和,等于前2根相等的木棒的长度。

由于各木棍的长度 \(a_i \leqslant 5000\),时间复杂度 \(O(n^2)\) 可过。考虑直接用两层循环,暴力枚举上述两种木棒的长度,计算方案数并累加。

外层循环为从长度为 \(i\) 的木棍中取出 \(2\) 根,方案数为 \(\rm C(cnt[i], 2)\)

内层循环为从剩余的木棍中取出两根长度之和为 \(i\) 的木棍。设其中一根长度为 \(j\), 则另外一根长度为 \(i-j\)

①若 \(j=i-j\),则方案数为从 \(\rm cnt[j]\) 中取出2个数的组合,即\(\rm C(cnt[j], 2)\)

②若 \(j≠i-j\),需从长度为 \(j\)\(i-j\) 的木棍中各取出一个,由乘法原理知方案数为 \(\rm C(cnt[j],2) \cdot C(cnt[i-j],2)\)

一定注意随时取模

#include <cstdio>
#include <algorithm>

using LL = long long;

const int N = 1e5 + 5, mod = 1e9 + 7;

int n, a[N], cnt[N];//cnt[i]表示长度为i的木棍个数

int main()
{
	scanf("%d", &n);
	int min = 1e9, max = -1e9;
	for (int i = 0; i < n; i++) {
		scanf("%d", &a[i]);
		cnt[a[i]]++;
		min = std::min(min, a[i]);
		max = std::max(max, a[i]);
	}
	
	LL ans = 0;
	for (int i = min; i <= max; i++) {
		if (cnt[i] >= 2) {//为保证可构成三角形,此长度的木棒数量 ≥2时才可进入内层循环。
		    LL times = cnt[i] * (cnt[i] - 1) / 2 % mod;
			for (int j = min; j <= i / 2; j++) {//为避免重复计算,规定j <= i - j
				if (j != i - j && cnt[j] >= 1 && cnt[i - j] >= 1) ans += times * cnt[j] * cnt[i - j] % mod;
				else if (j == i - j && cnt[j] >= 2) ans += times * (cnt[j] * (cnt[j] - 1) / 2) % mod;
			}
		}
	}
	printf("%lld", ans%mod);
	return 0;
}
posted @ 2024-02-16 09:26  胖柚の工作室  阅读(68)  评论(0)    收藏  举报