-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathsolution.lean
More file actions
148 lines (134 loc) · 7.58 KB
/
solution.lean
File metadata and controls
148 lines (134 loc) · 7.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import Mathlib
def countingFunctionN (k : Nat) (n : Nat) : Nat :=
let m := (k - 1) / 2
Finset.card (Finset.filter
(fun p : Nat × Nat => m + 1 ≤ p.1 + p.2 ∧ p.2 % k = (n * p.1) % k)
(Finset.Icc 1 m ×ˢ Finset.Icc 1 m))
def floorSumF (k : Nat) (a : Nat) : Nat :=
let m := (k - 1) / 2
∑ i ∈ Finset.Icc 1 m, (a * i + m) / k
lemma two_mul_m_eq (k : ℕ) (hk_odd : Odd k) : 2 * ((k - 1) / 2) = k - 1 := by
obtain ⟨t, ht⟩ := hk_odd; omega
lemma div_of_succ_mul (k n i m : ℕ) (hk_pos : 0 < k) :
((n + 1) * i + m) / k = (n * i + m) / k + ((n * i + m) % k + i) / k := by
set q := (n * i + m) / k; set r := (n * i + m) % k
have h_div_alg : k * q + r = n * i + m := Nat.div_add_mod (n * i + m) k
have h_expand : (n + 1) * i + m = k * q + (r + i) := by
calc (n + 1) * i + m = n * i + i + m := by ring
_ = n * i + m + i := by ring
_ = (k * q + r) + i := by rw [← h_div_alg]
_ = k * q + (r + i) := by ring
rw [h_expand, Nat.add_div_of_dvd_right (dvd_mul_right k q), Nat.mul_div_cancel_left q hk_pos]
lemma floor_diff_eq (k n i : ℕ) (hk_pos : 0 < k) :
((n + 1) * i + (k - 1) / 2) / k - (n * i + (k - 1) / 2) / k =
((n * i + (k - 1) / 2) % k + i) / k := by
simp only [div_of_succ_mul k n i ((k - 1) / 2) hk_pos, add_tsub_cancel_left]
lemma floor_sum_diff_nonneg (k n i : ℕ) :
(n * i + (k - 1) / 2) / k ≤ ((n + 1) * i + (k - 1) / 2) / k := by
exact Nat.div_le_div_right (by have h := Nat.mul_le_mul_right i (Nat.le_succ n); linarith)
lemma mod_eq_sub_when_large (k n i : ℕ) (hk_ge : 3 ≤ k) (hk_odd : Odd k)
(hr_large : (n * i) % k > (k - 1) / 2) :
(n * i + (k - 1) / 2) % k + k = (n * i) % k + (k - 1) / 2 := by
have h1 : ((k - 1) / 2) % k = (k - 1) / 2 := Nat.mod_eq_of_lt (by omega)
have h2 : k ≤ (n * i) % k + ((k - 1) / 2) % k := by obtain ⟨t, ht⟩ := hk_odd; omega
have h3 := Nat.add_mod_add_of_le_add_mod h2
omega
lemma floor_term_eq_indicator (k n i : ℕ) (hk_ge : 3 ≤ k) (hk_odd : Odd k)
(_hi_lo : 1 ≤ i) (hi_hi : i ≤ (k-1)/2) :
((n * i + (k - 1) / 2) % k + i) / k =
if (n * i) % k ∈ Finset.Icc 1 ((k-1)/2) ∧ i + (n * i) % k ≥ (k-1)/2 + 1 then 1 else 0 := by
by_cases h : (n * i) % k ∈ Finset.Icc 1 ((k-1)/2) ∧ i + (n * i) % k ≥ (k-1)/2 + 1
· rw [if_pos h]
have h1 : (n * i) % k ≤ (k - 1) / 2 := (Finset.mem_Icc.mp h.1).2
have h2 : (n * i + (k - 1) / 2) % k = (n * i) % k + (k - 1) / 2 := by
rw [Nat.add_mod, Nat.mod_eq_of_lt (by omega : (k - 1) / 2 < k)]
exact Nat.mod_eq_of_lt (by obtain ⟨t, ht⟩ := hk_odd; omega)
rw [h2]
apply Nat.div_eq_of_lt_le <;> (obtain ⟨t, ht⟩ := hk_odd; omega)
· rw [if_neg h]; push_neg at h
by_cases hr_small : (n * i) % k ≤ (k-1)/2
· by_cases hr_zero : (n * i) % k = 0
· simp only [Nat.add_mod, hr_zero, zero_add, Nat.mod_eq_of_lt (by omega : (k - 1) / 2 < k)]
exact Nat.div_eq_of_lt (by obtain ⟨m, hm⟩ := hk_odd; omega)
· have hr_in : (n * i) % k ∈ Finset.Icc 1 ((k-1)/2) := Finset.mem_Icc.mpr ⟨by omega, hr_small⟩
have hr_sum_small := h hr_in
have h1 : (n * i + (k - 1) / 2) % k = (n * i) % k + (k - 1) / 2 := by
rw [Nat.add_mod, Nat.mod_eq_of_lt (by omega : (k - 1) / 2 < k)]
exact Nat.mod_eq_of_lt (by obtain ⟨t, ht⟩ := hk_odd; omega)
rw [h1]
apply Nat.div_eq_of_lt
obtain ⟨t, ht⟩ := hk_odd
omega
· have h_mod_eq := mod_eq_sub_when_large k n i hk_ge hk_odd (by omega)
have h_2m := two_mul_m_eq k hk_odd
have h_r_lt_k : (n * i) % k < k := Nat.mod_lt _ (by omega)
exact Nat.div_eq_of_lt (by omega)
lemma count_for_fixed_i (k n i : ℕ) (hk_ge : 3 ≤ k) (_hi_lo : 1 ≤ i) (_hi_hi : i ≤ (k-1)/2) :
(Finset.filter (fun j => (k-1)/2 + 1 ≤ i + j ∧ j % k = (n * i) % k)
(Finset.Icc 1 ((k-1)/2))).card =
if (n * i) % k ∈ Finset.Icc 1 ((k-1)/2) ∧ i + (n * i) % k ≥ (k-1)/2 + 1 then 1 else 0 := by
have h1 : (Finset.filter (fun j => (k-1)/2 + 1 ≤ i + j ∧ j % k = (n * i) % k)
(Finset.Icc 1 ((k-1)/2))) =
if (n * i) % k ∈ Finset.Icc 1 ((k-1)/2) ∧ i + (n * i) % k ≥ (k-1)/2 + 1
then {(n * i) % k} else ∅ := by
split_ifs with h
· ext j
simp only [Finset.mem_filter, Finset.mem_Icc, Finset.mem_singleton]
constructor
· intro ⟨⟨hj_lo, hj_hi⟩, _, hj_mod⟩
rw [Nat.mod_eq_of_lt (by omega : j < k)] at hj_mod
exact hj_mod
· intro hj
have h_r_lo : 1 ≤ (n * i) % k := (Finset.mem_Icc.mp h.1).1
have h_r_hi : (n * i) % k ≤ (k - 1) / 2 := (Finset.mem_Icc.mp h.1).2
exact ⟨⟨by omega, by omega⟩, by omega, by simp [hj, Nat.mod_eq_of_lt (by omega : (n * i) % k < k)]⟩
· apply Finset.filter_eq_empty_iff.mpr
intro j hj; simp only [Finset.mem_Icc] at hj
intro hc
have hj_mod : j % k = j := Nat.mod_eq_of_lt (by omega)
have h_r_in : (n * i) % k ∈ Finset.Icc 1 ((k-1)/2) := by simp only [Finset.mem_Icc]; rw [hj_mod] at hc; omega
exact h ⟨h_r_in, by rw [hj_mod] at hc; omega⟩
rw [h1]; split_ifs <;> simp
lemma countingN_as_sum_over_i (k n : ℕ) :
countingFunctionN k n = ∑ i ∈ Finset.Icc 1 ((k-1)/2),
(Finset.filter (fun j => (k-1)/2 + 1 ≤ i + j ∧ j % k = (n * i) % k)
(Finset.Icc 1 ((k-1)/2))).card := by
simp only [countingFunctionN]
calc
(Finset.filter (fun p : ℕ × ℕ => (k - 1) / 2 + 1 ≤ p.1 + p.2 ∧ p.2 % k = (n * p.1) % k)
(Finset.Icc 1 ((k - 1) / 2) ×ˢ Finset.Icc 1 ((k - 1) / 2))).card
= ∑ x ∈ Finset.Icc 1 ((k - 1) / 2) ×ˢ Finset.Icc 1 ((k - 1) / 2),
if (k - 1) / 2 + 1 ≤ x.1 + x.2 ∧ x.2 % k = (n * x.1) % k then 1 else 0 := by
rw [← Finset.sum_filter]; simp
_ = ∑ i ∈ Finset.Icc 1 ((k - 1) / 2), ∑ j ∈ Finset.Icc 1 ((k - 1) / 2),
if (k - 1) / 2 + 1 ≤ i + j ∧ j % k = (n * i) % k then 1 else 0 := by rw [Finset.sum_product]
_ = ∑ i ∈ Finset.Icc 1 ((k - 1) / 2),
(Finset.filter (fun j => (k - 1) / 2 + 1 ≤ i + j ∧ j % k = (n * i) % k)
(Finset.Icc 1 ((k - 1) / 2))).card := by
apply Finset.sum_congr rfl; intro i _; rw [Finset.card_eq_sum_ones, ← Finset.sum_filter]
lemma countingN_eq_sum (k n : ℕ) (hk_ge : 3 ≤ k) (hk_odd : Odd k) :
countingFunctionN k n =
∑ i ∈ Finset.Icc 1 ((k - 1) / 2), ((n * i + (k - 1) / 2) % k + i) / k := by
rw [countingN_as_sum_over_i]
apply Finset.sum_congr rfl; intro i hi
rw [Finset.mem_Icc] at hi
rw [count_for_fixed_i k n i hk_ge hi.1 hi.2, floor_term_eq_indicator k n i hk_ge hk_odd hi.1 hi.2]
lemma floorSum_diff_eq_sum (k n : ℕ) (hk_ge : 3 ≤ k) :
floorSumF k (n + 1) - floorSumF k n =
∑ i ∈ Finset.Icc 1 ((k - 1) / 2), ((n * i + (k - 1) / 2) % k + i) / k := by
unfold floorSumF
rw [← Finset.sum_tsub_distrib]
· apply Finset.sum_congr rfl; intro i _; exact floor_diff_eq k n i (by omega)
· intro i _; exact floor_sum_diff_nonneg k n i
lemma cast_floorSum_diff (k n : ℕ) :
(floorSumF k (n + 1) : ℤ) - (floorSumF k n : ℤ) =
((floorSumF k (n + 1) - floorSumF k n : ℕ) : ℤ) := by
have h1 : floorSumF k (n + 1) ≥ floorSumF k n := by
simp only [floorSumF]; apply Finset.sum_le_sum; intro i _
exact Nat.div_le_div_right (by have h := Nat.mul_le_mul_right i (Nat.le_succ n); linarith)
omega
theorem main_theorem (k : ℕ) (n : ℕ)
(hk_ge : 3 ≤ k) (hk_odd : Odd k)
(_hn_coprime : Nat.Coprime n k) (_hn1_coprime : Nat.Coprime (n + 1) k) :
(countingFunctionN k n : ℤ) = (floorSumF k (n + 1) : ℤ) - (floorSumF k n : ℤ) := by
rw [cast_floorSum_diff k n, floorSum_diff_eq_sum k n hk_ge, countingN_eq_sum k n hk_ge hk_odd]