Triangles with Three Colors
Autumn Tournament (2016)
Submission name: triangle.cpp
Problem summary
Each segment has a length and one of three colors: b, g, r. Count choices of three distinct input segments that form a nondegenerate triangle and use all three colors. Equal-length segments remain separate choices.
Input
N, then N lines containing a color and a length.
Output
The number of valid triangles.
Constraints
1 ≤ N ≤ 6000; lengths are positive integers at most 100000.
Worked example
Original statement sample.
Input
5 r 10 g 10 b 12 r 5 g 6
Output
3
Solution analysis
- Sort every segment by length, keeping its color. For each right endpoint c, count pairs a<b<c whose lengths sum to more than length[c]. Since c is a largest side, this strict inequality is exactly the triangle condition.
- Use a left pointer a=0 and a middle pointer b=c−1. If length[a]+length[b] is too small, advance a. Otherwise every index from a through b−1 also makes a large-enough sum with b. Only the color different from both color[b] and color[c] is acceptable, and if those two colors agree the contribution is zero. Prefix color counts give the number of acceptable indices in [a,b) in O(1), after which decrement b.
- In the sample, the blue segment of length 12 can join red/green pairs (10,10), (10,6) and (5,10). Pair (5,6) fails because 5+6≤12, leaving three triangles. Index-based counting preserves multiplicities for equal lengths.
Why it works
At a fixed largest index c, the two-pointer argument partitions all pairs: a failed smallest value cannot work with any smaller b, while a successful b works with every remaining index ≥a. Prefix counts select exactly pairs with three different colors. Each triple has a unique largest sorted index, so it is counted once.
Watch out. Use a strict sum inequality to exclude degenerate triangles. Do not discard duplicate segments. When the two fixed colors match, no third color can make all three distinct.
Commented C++17 solution
An independently written complete program with standard headers.
#include<algorithm>
#include<array>
#include<iostream>
#include<vector>
using namespace std;
struct Segment{
int length;
int color;
};
int main(){
int n;
cin>>n;
vector<Segment>segments(n);
for(Segment&segment:segments){
char color;
cin>>color>>segment.length;
segment.color=color=='b'?0:color=='g'?1:2;
}
sort(segments.begin(),segments.end(),[](const Segment&a,const Segment&b){
return a.length<b.length;
});
vector<array<int,3>>prefix(n+1);
for(int i=0;i<n;i++){
prefix[i+1]=prefix[i];
prefix[i+1][segments[i].color]++;
}
long long answer=0;
for(int largest=2;largest<n;largest++){
int left=0;
int right=largest-1;
while(left<right){
if(segments[left].length+segments[right].length<=segments[largest].length){
left++;
}
else{
if(segments[right].color!=segments[largest].color){
int missing=3-segments[right].color-segments[largest].color;
// Count the required third color among [left, right).
answer+=prefix[right][missing]-prefix[left][missing];
}
right--;
}
}
}
cout<<answer<<'\n';
}