cppAcademy
FROM LEARNING TO COMPETING

Real problems.
Your next challenge.

Explore the Group C Olympiad and Autumn Tournament archive.
Choose a topic. Find a challenge. Build your solution.

274 tasks: 213 from the Municipal, Regional, and National Olympiad rounds (2009–2026), 57 Autumn Tournament tasks (2007–2025), and 4 previously featured problems. 207 tasks have independently written English summaries, analyses, and C++17 solutions; the remaining entries link to Arena. Difficulty labels are learning estimates, not official ratings. Special formats and source clarifications are explained on affected tasks.
GROUP C2016 · MediumSorting and two pointers

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

  1. 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.
  2. 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.
  3. 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.

Complexity: O(N²) time and O(N) space. Each fixed largest index uses two monotone pointers; prefix color counts occupy three arrays. Use long long because color-balanced inputs can have billions of triangles.

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';
}

Source: Arena Olimpiici ↗