```go
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
func main() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var n, m int
fmt.Fscan(in, &n, &m)
w1 := make([]int64, 0)
w2 := make([]int64, 0)
w3 := make([]int64, 0)
for i := 0; i < n; i++ {
var wi int
var ci int64
fmt.Fscan(in, &wi, &ci)
if wi == 1 {
w1 = append(w1, ci)
} else if wi == 2 {
w2 = append(w2, ci)
} else {
w3 = append(w3, ci)
}
}
sort.Slice(w1, func(i, j int) bool { return w1[i] > w1[j] })
sort.Slice(w2, func(i, j int) bool { return w2[i] > w2[j] })
sort.Slice(w3, func(i, j int) bool { return w3[i] > w3[j] })
pref1 := make([]int64, len(w1)+1)
for i := 0; i < len(w1); i++ {
pref1[i+1] = pref1[i] + w1[i]
}
pref2 := make([]int64, len(w2)+1)
for i := 0; i < len(w2); i++ {
pref2[i+1] = pref2[i] + w2[i]
}
pref3 := make([]int64, len(w3)+1)
for i := 0; i < len(w3); i++ {
pref3[i+1] = pref3[i] + w3[i]
}
var ans int64 = 0
maxI := len(w3)
if m/3 < maxI {
maxI = m / 3
}
for i := 0; i <= maxI; i++ {
rem := m - 3*i
val := pref3[i] + solve12(rem, pref1, pref2)
if val > ans {
ans = val
}
}
fmt.Fprintln(out, ans)
}
func solve12(R int, pref1, pref2 []int64) int64 {
len1 := len(pref1) - 1
len2 := len(pref2) - 1
maxJ := R / 2
if maxJ > len2 {
maxJ = len2
}
if maxJ < 0 {
return 0
}
low, high := 0, maxJ
for high-low > 3 {
m1 := low + (high-low)/3
m2 := high - (high-low)/3
k1 := R - 2*m1
if k1 > len1 {
k1 = len1
}
f1 := pref2[m1] + pref1[k1]
k2 := R - 2*m2
if k2 > len1 {
k2 = len1
}
f2 := pref2[m2] + pref1[k2]
if f1 < f2 {
low = m1
} else {
high = m2
}
}
var best int64 = 0
for j := low; j <= high; j++ {
k := R - 2*j
if k > len1 {
k = len1
}
val := pref2[j] + pref1[k]
if val > best {
best = val
}
}
return best
}
```