CSES' movie festival question
```
int main() {
int n;
cin >> n;
vector<pair<int, int>> ms(n);
for (int i = 0; i < n; ++i) {
cin >> ms[i].first >> ms[i].second;
}
std::sort(ms.begin(), ms.end(), [](pair<int, int> p1, pair<int, int> p2) {
return (p1.second < p2.second) ||
(p1.second == p2.second && p1.first < p2.first);
});
int njobs = 0;
int cur_end = -1;
for (int i = 0; i < n; ++i) {
if (cur_end <= ms[i].first) {
cur_end = ms[i].second;
njobs++;
}
}
cout << njobs << "\n";
return 0;
}
```

#### § Explanation 1: exchange argument

- The idea is to pick jobs
*greedily *, based on *quickest finishing time *. - The argument of optimality is strategy stealing. Think of the first job in our ordering
`O`

versus the optimal ordering `O*`

. - If we both use the same job, ie,
`O[1] = O*[1]`

, recurse into the second job. - If we use different jobs then
`O[1] != O*[1]`

. - Since
`O[1]`

ends *quickest * [acc to our algorithm ], we will have that `end(O[1]) < end(all other jobs)`

, hence `end(O[1]) < end(O*[1])`

. - Since
`O*`

is a *correct * job schedule, we have that `end(O*[1]) < start(O*[2])`

. - Chaining inequalities, we get that
`end(O[1]) < end(O*[1]) < start(O*[2])`

. - Thus, we can create
`O~`

which has `O~[1] = O[1]`

and `O~[rest] = O*[rest]`

. ( `~`

for "modified"). - Now recurse into
`O~`

to continue aligning `O*`

with `O`

. We continue to have the same length between `O~`

, `O`

and `O*`

.

#### § Explanation 2: posets and interval orders