Straight Lines
National Olympiad — Municipal round (2011 season)
Submission name: lines.cpp
Problem summary
Given lines ax+by+c=0, count distinct geometric lines and distinct parallelism classes. Coincident lines belong to the same class.
Input
N, followed by N triples a b c.
Output
Two lines: the number of distinct lines, then the number of direction classes.
Constraints
N ≤ 1000; integer coefficients in [−1000,1000]; (a,b) ≠ (0,0).
Worked example
Official statement example.
Input
6 1 -1 2 2 3 -4 -3 3 -6 -4 10 8 6 -15 -20 -2 5 4
Output
4 3
Solution analysis
- Two triples represent the same line exactly when they differ by a nonzero common scalar. Divide all three coefficients by gcd(|a|,|b|,|c|) and fix the sign so the first nonzero entry among a,b is positive.
- For parallelism ignore c and separately normalize the pair (a,b) by gcd(|a|,|b|), with the same sign rule. Insert normalized triples and pairs into ordered sets. Their sizes are the requested answers.
- In the sample, (1,−1,2) and (−3,3,−6) normalize to the same triple. The triples (−4,10,8) and (−2,5,4) also coincide, while (6,−15,−20) shares their direction but is a different line.
Why it works
Primitive integer proportional vectors differ only by sign. The sign convention removes that ambiguity, so equal normalized triples are equivalent exactly to coincident lines. The same argument on normal-vector pairs characterizes parallel lines. Sets therefore count the two equivalence relations exactly.
Watch out. Normalize direction independently of the full triple.,Vertical and horizontal lines require no floating-point special cases.
Commented C++17 solution
An independently written complete program with standard headers.
// Key idea: Primitive integer proportional vectors differ only by sign. The sign convention removes
// that ambiguity, so equal normalized triples are equivalent exactly to coincident lines.
#include<array>
#include<cstdlib>
#include<iostream>
#include<numeric>
#include<set>
#include<utility>
using namespace std;
int main(){
int n;
cin>>n;
set<array<int,3>>lines;
set<pair<int,int>>directions;
while(n--){
int a,b,c;
cin>>a>>b>>c;
if(a<0||(a==0&&b<0)){
a=-a;
b=-b;
c=-c;
}
int g=gcd(abs(a),abs(b));
directions.insert({a/g,b/g});
g=gcd(g,abs(c));
lines.insert({a/g,b/g,c/g});
}
cout<<lines.size()<<'\n'<<directions.size()<<'\n';
}