Skip to content

Commit db9fb24

Browse files
mo271Parcly-Taxel
andcommitted
feat: port Archive.Imo.Imo1998Q2 (leanprover-community#5157)
Co-authored-by: Moritz Firsching <firsching@google.com> Co-authored-by: Jeremy Tan Jie Rui <reddeloostw@gmail.com>
1 parent ef8a6a9 commit db9fb24

File tree

2 files changed

+265
-0
lines changed

2 files changed

+265
-0
lines changed

Archive.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Archive.Imo.Imo1981Q3
1313
import Archive.Imo.Imo1987Q1
1414
import Archive.Imo.Imo1988Q6
1515
import Archive.Imo.Imo1994Q1
16+
import Archive.Imo.Imo1998Q2
1617
import Archive.Imo.Imo2001Q2
1718
import Archive.Imo.Imo2001Q6
1819
import Archive.Imo.Imo2005Q3

Archive/Imo/Imo1998Q2.lean

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
/-
2+
Copyright (c) 2020 Oliver Nash. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Oliver Nash
5+
6+
! This file was ported from Lean 3 source module imo.imo1998_q2
7+
! leanprover-community/mathlib commit 308826471968962c6b59c7ff82a22757386603e3
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.Data.Fintype.Prod
12+
import Mathlib.Data.Int.Parity
13+
import Mathlib.Algebra.BigOperators.Order
14+
import Mathlib.Tactic.Ring
15+
import Mathlib.Tactic.NoncommRing
16+
17+
/-!
18+
# IMO 1998 Q2
19+
In a competition, there are `a` contestants and `b` judges, where `b ≥ 3` is an odd integer. Each
20+
judge rates each contestant as either "pass" or "fail". Suppose `k` is a number such that, for any
21+
two judges, their ratings coincide for at most `k` contestants. Prove that `k / a ≥ (b - 1) / (2b)`.
22+
23+
## Solution
24+
The problem asks us to think about triples consisting of a contestant and two judges whose ratings
25+
agree for that contestant. We thus consider the subset `A ⊆ C × JJ` of all such incidences of
26+
agreement, where `C` and `J` are the sets of contestants and judges, and `JJ = J × J - {(j, j)}`. We
27+
have natural maps: `left : A → C` and `right: A → JJ`. We count the elements of `A` in two ways: as
28+
the sum of the cardinalities of the fibres of `left` and as the sum of the cardinalities of the
29+
fibres of `right`. We obtain an upper bound on the cardinality of `A` from the count for `right`,
30+
and a lower bound from the count for `left`. These two bounds combine to the required result.
31+
32+
First consider the map `right : A → JJ`. Since the size of any fibre over a point in JJ is bounded
33+
by `k` and since `|JJ| = b^2 - b`, we obtain the upper bound: `|A| ≤ k(b^2-b)`.
34+
35+
Now consider the map `left : A → C`. The fibre over a given contestant `c ∈ C` is the set of
36+
ordered pairs of (distinct) judges who agree about `c`. We seek to bound the cardinality of this
37+
fibre from below. Minimum agreement for a contestant occurs when the judges' ratings are split as
38+
evenly as possible. Since `b` is odd, this occurs when they are divided into groups of size
39+
`(b-1)/2` and `(b+1)/2`. This corresponds to a fibre of cardinality `(b-1)^2/2` and so we obtain
40+
the lower bound: `a(b-1)^2/2 ≤ |A|`.
41+
42+
Rearranging gives the result.
43+
-/
44+
45+
46+
-- porting note: `A` already upper case
47+
set_option linter.uppercaseLean3 false
48+
49+
open scoped Classical
50+
51+
variable {C J : Type _} (r : C → J → Prop)
52+
53+
namespace Imo1998Q2
54+
55+
noncomputable section
56+
57+
/-- An ordered pair of judges. -/
58+
abbrev JudgePair (J : Type _) :=
59+
J × J
60+
#align imo1998_q2.judge_pair Imo1998Q2.JudgePair
61+
62+
/-- A triple consisting of contestant together with an ordered pair of judges. -/
63+
abbrev AgreedTriple (C J : Type _) :=
64+
C × JudgePair J
65+
#align imo1998_q2.agreed_triple Imo1998Q2.AgreedTriple
66+
67+
/-- The first judge from an ordered pair of judges. -/
68+
abbrev JudgePair.judge₁ : JudgePair J → J :=
69+
Prod.fst
70+
#align imo1998_q2.judge_pair.judge₁ Imo1998Q2.JudgePair.judge₁
71+
72+
/-- The second judge from an ordered pair of judges. -/
73+
abbrev JudgePair.judge₂ : JudgePair J → J :=
74+
Prod.snd
75+
#align imo1998_q2.judge_pair.judge₂ Imo1998Q2.JudgePair.judge₂
76+
77+
/-- The proposition that the judges in an ordered pair are distinct. -/
78+
abbrev JudgePair.Distinct (p : JudgePair J) :=
79+
p.judge₁ ≠ p.judge₂
80+
#align imo1998_q2.judge_pair.distinct Imo1998Q2.JudgePair.Distinct
81+
82+
/-- The proposition that the judges in an ordered pair agree about a contestant's rating. -/
83+
abbrev JudgePair.Agree (p : JudgePair J) (c : C) :=
84+
r c p.judge₁ ↔ r c p.judge₂
85+
#align imo1998_q2.judge_pair.agree Imo1998Q2.JudgePair.Agree
86+
87+
/-- The contestant from the triple consisting of a contestant and an ordered pair of judges. -/
88+
abbrev AgreedTriple.contestant : AgreedTriple C J → C :=
89+
Prod.fst
90+
#align imo1998_q2.agreed_triple.contestant Imo1998Q2.AgreedTriple.contestant
91+
92+
/-- The ordered pair of judges from the triple consisting of a contestant and an ordered pair of
93+
judges. -/
94+
abbrev AgreedTriple.judgePair : AgreedTriple C J → JudgePair J :=
95+
Prod.snd
96+
#align imo1998_q2.agreed_triple.judge_pair Imo1998Q2.AgreedTriple.judgePair
97+
98+
@[simp]
99+
theorem JudgePair.agree_iff_same_rating (p : JudgePair J) (c : C) :
100+
p.Agree r c ↔ (r c p.judge₁ ↔ r c p.judge₂) :=
101+
Iff.rfl
102+
#align imo1998_q2.judge_pair.agree_iff_same_rating Imo1998Q2.JudgePair.agree_iff_same_rating
103+
104+
/-- The set of contestants on which two judges agree. -/
105+
def agreedContestants [Fintype C] (p : JudgePair J) : Finset C :=
106+
Finset.univ.filter fun c => p.Agree r c
107+
#align imo1998_q2.agreed_contestants Imo1998Q2.agreedContestants
108+
section
109+
110+
variable [Fintype J] [Fintype C]
111+
112+
/-- All incidences of agreement. -/
113+
def A : Finset (AgreedTriple C J) :=
114+
Finset.univ.filter @fun (a : AgreedTriple C J) =>
115+
(a.judgePair.Agree r a.contestant ∧ a.judgePair.Distinct)
116+
#align imo1998_q2.A Imo1998Q2.A
117+
118+
theorem A_maps_to_offDiag_judgePair (a : AgreedTriple C J) :
119+
a ∈ A r → a.judgePair ∈ Finset.offDiag (@Finset.univ J _) := by simp [A, Finset.mem_offDiag]
120+
#align imo1998_q2.A_maps_to_off_diag_judge_pair Imo1998Q2.A_maps_to_offDiag_judgePair
121+
122+
theorem A_fibre_over_contestant (c : C) :
123+
(Finset.univ.filter fun p : JudgePair J => p.Agree r c ∧ p.Distinct) =
124+
((A r).filter fun a : AgreedTriple C J => a.contestant = c).image Prod.snd := by
125+
ext p
126+
simp only [A, Finset.mem_univ, Finset.mem_filter, Finset.mem_image, true_and_iff, exists_prop]
127+
constructor
128+
· rintro ⟨h₁, h₂⟩; refine' ⟨(c, p), _⟩; tauto
129+
· intro h; aesop
130+
#align imo1998_q2.A_fibre_over_contestant Imo1998Q2.A_fibre_over_contestant
131+
132+
theorem A_fibre_over_contestant_card (c : C) :
133+
(Finset.univ.filter fun p : JudgePair J => p.Agree r c ∧ p.Distinct).card =
134+
((A r).filter fun a : AgreedTriple C J => a.contestant = c).card := by
135+
rw [A_fibre_over_contestant r]
136+
apply Finset.card_image_of_injOn
137+
-- porting note: used to be `tidy`. TODO: remove `ext` after `extCore` to `aesop`.
138+
unfold Set.InjOn; intros; ext; all_goals aesop
139+
#align imo1998_q2.A_fibre_over_contestant_card Imo1998Q2.A_fibre_over_contestant_card
140+
141+
theorem A_fibre_over_judgePair {p : JudgePair J} (h : p.Distinct) :
142+
agreedContestants r p = ((A r).filter fun a : AgreedTriple C J => a.judgePair = p).image
143+
AgreedTriple.contestant := by
144+
dsimp only [A, agreedContestants]; ext c; constructor <;> intro h
145+
· rw [Finset.mem_image]; refine' ⟨⟨c, p⟩, _⟩; aesop
146+
-- porting note: this used to be `finish`
147+
· simp only [Finset.mem_filter, Finset.mem_image, Prod.exists] at h
148+
rcases h with ⟨_, ⟨_, ⟨_, ⟨h, _⟩⟩⟩⟩
149+
cases h; aesop
150+
#align imo1998_q2.A_fibre_over_judge_pair Imo1998Q2.A_fibre_over_judgePair
151+
152+
theorem A_fibre_over_judgePair_card {p : JudgePair J} (h : p.Distinct) :
153+
(agreedContestants r p).card =
154+
((A r).filter fun a : AgreedTriple C J => a.judgePair = p).card := by
155+
rw [A_fibre_over_judgePair r h]
156+
apply Finset.card_image_of_injOn
157+
-- porting note: used to be `tidy`
158+
unfold Set.InjOn; intros; ext; all_goals aesop
159+
#align imo1998_q2.A_fibre_over_judge_pair_card Imo1998Q2.A_fibre_over_judgePair_card
160+
161+
theorem A_card_upper_bound {k : ℕ}
162+
(hk : ∀ p : JudgePair J, p.Distinct → (agreedContestants r p).card ≤ k) :
163+
(A r).card ≤ k * (Fintype.card J * Fintype.card J - Fintype.card J) := by
164+
change _ ≤ k * (Finset.card _ * Finset.card _ - Finset.card _)
165+
rw [← Finset.offDiag_card]
166+
apply Finset.card_le_mul_card_image_of_maps_to (A_maps_to_offDiag_judgePair r)
167+
intro p hp
168+
have hp' : p.Distinct := by simp [Finset.mem_offDiag] at hp ; exact hp
169+
rw [← A_fibre_over_judgePair_card r hp']; apply hk; exact hp'
170+
#align imo1998_q2.A_card_upper_bound Imo1998Q2.A_card_upper_bound
171+
172+
end
173+
174+
theorem add_sq_add_sq_sub {α : Type _} [Ring α] (x y : α) :
175+
(x + y) * (x + y) + (x - y) * (x - y) = 2 * x * x + 2 * y * y := by noncomm_ring
176+
#align imo1998_q2.add_sq_add_sq_sub Imo1998Q2.add_sq_add_sq_sub
177+
178+
theorem norm_bound_of_odd_sum {x y z : ℤ} (h : x + y = 2 * z + 1) :
179+
2 * z * z + 2 * z + 1 ≤ x * x + y * y := by
180+
suffices 4 * z * z + 4 * z + 1 + 12 * x * x + 2 * y * y by
181+
rw [← mul_le_mul_left (zero_lt_two' ℤ)]; ring_nf at this ⊢; exact this
182+
have h' : (x + y) * (x + y) = 4 * z * z + 4 * z + 1 := by rw [h]; ring
183+
rw [← add_sq_add_sq_sub, h', add_le_add_iff_left]
184+
suffices 0 < (x - y) * (x - y) by apply Int.add_one_le_of_lt this
185+
rw [mul_self_pos, sub_ne_zero]; apply Int.ne_of_odd_add ⟨z, h⟩
186+
#align imo1998_q2.norm_bound_of_odd_sum Imo1998Q2.norm_bound_of_odd_sum
187+
188+
section
189+
190+
variable [Fintype J]
191+
192+
theorem judge_pairs_card_lower_bound {z : ℕ} (hJ : Fintype.card J = 2 * z + 1) (c : C) :
193+
2 * z * z + 2 * z + 1 ≤ (Finset.univ.filter fun p : JudgePair J => p.Agree r c).card := by
194+
let x := (Finset.univ.filter fun j => r c j).card
195+
let y := (Finset.univ.filter fun j => ¬r c j).card
196+
have h : (Finset.univ.filter fun p : JudgePair J => p.Agree r c).card = x * x + y * y := by
197+
simp [← Finset.filter_product_card]
198+
rw [h]; apply Int.le_of_ofNat_le_ofNat; simp only [Int.ofNat_add, Int.ofNat_mul]
199+
apply norm_bound_of_odd_sum
200+
suffices x + y = 2 * z + 1 by simp [← Int.ofNat_add, this]
201+
rw [Finset.filter_card_add_filter_neg_card_eq_card, ← hJ]; rfl
202+
#align imo1998_q2.judge_pairs_card_lower_bound Imo1998Q2.judge_pairs_card_lower_bound
203+
204+
theorem distinct_judge_pairs_card_lower_bound {z : ℕ} (hJ : Fintype.card J = 2 * z + 1) (c : C) :
205+
2 * z * z ≤ (Finset.univ.filter fun p : JudgePair J => p.Agree r c ∧ p.Distinct).card := by
206+
let s := Finset.univ.filter fun p : JudgePair J => p.Agree r c
207+
let t := Finset.univ.filter fun p : JudgePair J => p.Distinct
208+
have hs : 2 * z * z + 2 * z + 1 ≤ s.card := judge_pairs_card_lower_bound r hJ c
209+
have hst : s \ t = Finset.univ.diag := by
210+
ext p; constructor <;> intros
211+
· aesop
212+
· suffices p.judge₁ = p.judge₂ by simp [this]
213+
aesop
214+
have hst' : (s \ t).card = 2 * z + 1 := by rw [hst, Finset.diag_card, ← hJ]; rfl
215+
rw [Finset.filter_and, ← Finset.sdiff_sdiff_self_left s t, Finset.card_sdiff]
216+
· rw [hst']; rw [add_assoc] at hs ; apply le_tsub_of_add_le_right hs
217+
· apply Finset.sdiff_subset
218+
#align imo1998_q2.distinct_judge_pairs_card_lower_bound Imo1998Q2.distinct_judge_pairs_card_lower_bound
219+
220+
theorem A_card_lower_bound [Fintype C] {z : ℕ} (hJ : Fintype.card J = 2 * z + 1) :
221+
2 * z * z * Fintype.card C ≤ (A r).card := by
222+
have h : ∀ a, a ∈ A r → Prod.fst a ∈ @Finset.univ C _ := by intros; apply Finset.mem_univ
223+
apply Finset.mul_card_image_le_card_of_maps_to h
224+
intro c _
225+
rw [← A_fibre_over_contestant_card]
226+
apply distinct_judge_pairs_card_lower_bound r hJ
227+
#align imo1998_q2.A_card_lower_bound Imo1998Q2.A_card_lower_bound
228+
229+
end
230+
231+
theorem clear_denominators {a b k : ℕ} (ha : 0 < a) (hb : 0 < b) :
232+
(b - 1 : ℚ) / (2 * b) ≤ k / a ↔ ((b : ℕ) - 1) * a ≤ k * (2 * b) := by
233+
rw [div_le_div_iff]
234+
-- porting note: proof used to finish with `<;> norm_cast <;> simp [ha, hb]`
235+
· convert @Nat.cast_le ℚ _ _ _ _
236+
· aesop
237+
· norm_cast
238+
all_goals simp [ha, hb]
239+
#align imo1998_q2.clear_denominators Imo1998Q2.clear_denominators
240+
241+
end
242+
243+
end Imo1998Q2
244+
245+
open Imo1998Q2
246+
247+
theorem imo1998_q2 [Fintype J] [Fintype C] (a b k : ℕ) (hC : Fintype.card C = a)
248+
(hJ : Fintype.card J = b) (ha : 0 < a) (hb : Odd b)
249+
(hk : ∀ p : JudgePair J, p.Distinct → (agreedContestants r p).card ≤ k) :
250+
(b - 1 : ℚ) / (2 * b) ≤ k / a := by
251+
rw [clear_denominators ha hb.pos]
252+
obtain ⟨z, hz⟩ := hb; rw [hz] at hJ ; rw [hz]
253+
have h := le_trans (A_card_lower_bound r hJ) (A_card_upper_bound r hk)
254+
rw [hC, hJ] at h
255+
-- We are now essentially done; we just need to bash `h` into exactly the right shape.
256+
have hl : k * ((2 * z + 1) * (2 * z + 1) - (2 * z + 1)) = k * (2 * (2 * z + 1)) * z := by
257+
have : 0 < 2 * z + 1 := by aesop
258+
simp only [mul_comm, add_mul, one_mul, nonpos_iff_eq_zero, add_tsub_cancel_right]; ring
259+
have hr : 2 * z * z * a = 2 * z * a * z := by ring
260+
rw [hl, hr] at h
261+
cases' z with z
262+
· simp
263+
· exact le_of_mul_le_mul_right h z.succ_pos
264+
#align imo1998_q2 imo1998_q2

0 commit comments

Comments
 (0)