package main
import (
"bufio"
"fmt"
"os"
"sort"
)
type Shoe struct {
price, id int
}
type Customer struct {
money, id int
}
type ShoeInfo struct {
price, id int
exists bool
}
type State struct {
prev_mask int
opt int
k int
}
func nextInt(scanner *bufio.Scanner) int {
if !scanner.Scan() {
return 0
}
res := 0
for _, b := range scanner.Bytes() {
res = res*10 + int(b-'0')
}
return res
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
scanner.Buffer(make([]byte, 1024*1024), 1024*1024)
n := nextInt(scanner)
if n == 0 {
return
}
shoes := make(map[int]Shoe, n)
sizesMap := make(map[int]bool)
for i := 1; i <= n; i++ {
c := nextInt(scanner)
s := nextInt(scanner)
shoes[s] = Shoe{price: c, id: i}
sizesMap[s] = true
}
m := nextInt(scanner)
custMap := make(map[int][]Customer, m)
for i := 1; i <= m; i++ {
d := nextInt(scanner)
l := nextInt(scanner)
custMap[l] = append(custMap[l], Customer{money: d, id: i})
sizesMap[l] = true
}
uniqueSizes := make([]int, 0, len(sizesMap))
for s := range sizesMap {
uniqueSizes = append(uniqueSizes, s)
}
sort.Ints(uniqueSizes)
U := len(uniqueSizes)
shoeInfo := make([]ShoeInfo, U)
custInfo := make([][]Customer, U)
for i, s := range uniqueSizes {
if sh, ok := shoes[s]; ok {
shoeInfo[i] = ShoeInfo{price: sh.price, id: sh.id, exists: true}
}
if cu, ok := custMap[s]; ok {
sort.Slice(cu, func(a, b int) bool {
return cu[a].money > cu[b].money
})
if len(cu) > 2 {
cu = cu[:2]
}
custInfo[i] = cu
}
}
dp := make([][4]int64, U+1)
parent := make([][4]State, U+1)
for i := 0; i <= U; i++ {
for j := 0; j < 4; j++ {
dp[i][j] = -1
}
}
dp[0][0] = 0
for i := 1; i <= U; i++ {
s_curr := uniqueSizes[i-1]
s_prev := -1
if i > 1 {
s_prev = uniqueSizes[i-2]
}
P := 0
if i > 1 {
P = len(custInfo[i-2])
}
N := len(custInfo[i-1])
full_mask := (1 << N) - 1
shoe := shoeInfo[i-1]
for prev_mask := 0; prev_mask < (1 << P); prev_mask++ {
if dp[i-1][prev_mask] == -1 {
continue
}
val := dp[i-1][prev_mask]
new_mask := full_mask
if val > dp[i][new_mask] {
dp[i][new_mask] = val
parent[i][new_mask] = State{prev_mask, 0, -1}
}
if shoe.exists && i > 1 && s_curr == s_prev+1 {
for k := 0; k < P; k++ {
if (prev_mask & (1 << k)) != 0 {
if custInfo[i-2][k].money >= shoe.price {
val1 := dp[i-1][prev_mask] + int64(shoe.price)
nm1 := full_mask
if val1 > dp[i][nm1] {
dp[i][nm1] = val1
parent[i][nm1] = State{prev_mask, 1, k}
}
}
}
}
}
if shoe.exists {
for k := 0; k < N; k++ {
if custInfo[i-1][k].money >= shoe.price {
val2 := dp[i-1][prev_mask] + int64(shoe.price)
nm2 := full_mask & ^(1 << k)
if val2 > dp[i][nm2] {
dp[i][nm2] = val2
parent[i][nm2] = State{prev_mask, 2, k}
}
}
}
}
}
}
var max_val int64 = -1
best_mask := 0
for m_mask := 0; m_mask < 4; m_mask++ {
if dp[U][m_mask] > max_val {
max_val = dp[U][m_mask]
best_mask = m_mask
}
}
type Match struct {
custId, shoeId int
}
var matches []Match
curr_mask := best_mask
for i := U; i >= 1; i-- {
st := parent[i][curr_mask]
if st.opt == 1 {
matches = append(matches, Match{custInfo[i-2][st.k].id, shoeInfo[i-1].id})
} else if st.opt == 2 {
matches = append(matches, Match{custInfo[i-1][st.k].id, shoeInfo[i-1].id})
}
curr_mask = st.prev_mask
}
fmt.Println(max_val)
fmt.Println(len(matches))
for _, m_match := range matches {
fmt.Printf("%d %d\n", m_match.custId, m_match.shoeId)
}
}