题目描述
给定一个圆上的 NNN 个点,以及相邻点之间的圆弧长度。你需要计算能够用这些点作为顶点构造出的不同的等边三角形的数量。
输入的第一行是一个整数 NNN,表示点的数量。第二行是 NNN 个整数 XiX_iXi,表示相邻点之间的弧长(按顺序 X1X_1X1 是点 111 到点 222 的弧长,XNX_NXN 是点 NNN 到点 111 的弧长)。
输出一个整数,表示可以构造的不同的等边三角形的数量。
数据范围:
- 3≤N≤1053 \leq N \leq 10^53≤N≤105
- 1≤Xi≤1031 \leq X_i \leq 10^31≤Xi≤103
题目分析
1. 等边三角形在圆上的性质
在圆上构造等边三角形,意味着三个顶点必须将圆周三等分。也就是说,如果圆周总长为 CCC,那么三个顶点之间的圆弧长度必须都是 C/3C/3C/3。
因此,如果从某个点 ppp 出发,沿着圆走 C/3C/3C/3 的弧长到达点 qqq,再走 C/3C/3C/3 到达点 rrr,再走 C/3C/3C/3 回到 ppp,那么 p,q,rp, q, rp,q,r 就构成一个等边三角形。
2. 基本思路
-
计算总周长
C=∑i=1NXi C = \sum_{i=1}^{N} X_i C=i=1∑NXi
如果 CCC 不能被 333 整除,那么不可能构造任何等边三角形,直接输出 000。 -
前缀和表示点的位置
我们可以将圆展开,用前缀和表示每个点相对于起点 000 的位置(弧长)。
设:
prefix[0]=0 prefix[0] = 0 prefix[0]=0
prefix[i]=X1+X2+⋯+Xifor 1≤i≤N prefix[i] = X_1 + X_2 + \dots + X_i \quad \text{for } 1 \leq i \leq N prefix[i]=X1+X2+⋯+Xifor 1≤i≤N
注意 prefix[N]=Cprefix[N] = Cprefix[N]=C。 -
判断三等分点是否存在
对于每个起点 iii(位置为 prefix[i]prefix[i]prefix[i]),我们希望找到另外两个点 jjj 和 kkk,使得:
prefix[j]≡prefix[i]+C3(modC) prefix[j] \equiv prefix[i] + \frac{C}{3} \pmod{C} prefix[j]≡prefix[i]+3C(modC)
prefix[k]≡prefix[i]+2C3(modC) prefix[k] \equiv prefix[i] + \frac{2C}{3} \pmod{C} prefix[k]≡prefix[i]+32C(modC)
如果这两个位置都存在于前缀和集合中,则 (i,j,k)(i, j, k)(i,j,k) 构成一个等边三角形。 -
避免重复计数
每个三角形会被它的三个顶点各作为起点统计一次,因此最后的总数需要除以 333。
3. 算法步骤
- 读入 NNN 和 XiX_iXi,计算总周长 CCC。
- 如果 C%3≠0C \% 3 \neq 0C%3=0,输出 000 并结束。
- 计算前缀和数组 prefixprefixprefix。
- 将前缀和存入哈希集合,以便 O(1)O(1)O(1) 查找。
- 遍历每个起点 iii,检查 prefix[i]+C/3prefix[i] + C/3prefix[i]+C/3 和 prefix[i]+2C/3prefix[i] + 2C/3prefix[i]+2C/3 是否在集合中(取模 CCC)。
- 统计满足条件的起点数量,最后除以 333 得到答案。
4. 复杂度分析
- 时间复杂度:O(N)O(N)O(N),因为每个点只遍历一次,哈希查找是 O(1)O(1)O(1)。
- 空间复杂度:O(N)O(N)O(N),用于存储前缀和和哈希集合。
代码
// Triangles
// UVa ID: 12651
// Verdict: Accepted
// Submission Date: 2025-11-05
// UVa Run Time: 0.060s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int N;
while (cin >> N) {
vector<int> X(N);
long long total = 0;
for (int i = 0; i < N; ++i) {
cin >> X[i];
total += X[i];
}
// 如果总周长不能被3整除,无法构造等边三角形
if (total % 3 != 0) {
cout << "0\n";
continue;
}
// 计算前缀和
vector<long long> prefix(N + 1, 0);
for (int i = 0; i < N; ++i) {
prefix[i + 1] = prefix[i] + X[i];
}
// 将前缀和存入哈希集合,方便快速查找
unordered_set<long long> prefixSet(prefix.begin(), prefix.end());
long long third = total / 3;
int count = 0;
// 遍历每个起点
for (int i = 0; i < N; ++i) {
long long target1 = prefix[i] + third;
long long target2 = prefix[i] + 2 * third;
// 处理循环,取模 total
if (target1 > total) target1 -= total;
if (target2 > total) target2 -= total;
// 如果两个目标位置都存在,则构成三角形
if (prefixSet.count(target1) && prefixSet.count(target2)) {
count++;
}
}
// 每个三角形被三个起点各统计一次
cout << count / 3 << "\n";
}
return 0;
}
总结
本题的关键在于理解圆上等边三角形的几何性质:三个顶点必须将圆周三等分。利用前缀和和哈希集合,我们可以高效地判断是否存在这样的三个点,并避免重复计数。算法的时间复杂度为 O(N)O(N)O(N),可以处理 N≤105N \leq 10^5N≤105 的大数据范围。
422

被折叠的 条评论
为什么被折叠?



