```go
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var n, m int
fmt.Fscan(reader, &n, &m)
grid := make([]string, n)
for i := 0; i < n; i++ {
fmt.Fscan(reader, &grid[i])
}
up := make([][]int, n)
down := make([][]int, n)
left := make([][]int, n)
right := make([][]int, n)
for i := 0; i < n; i++ {
up[i] = make([]int, m)
down[i] = make([]int, m)
left[i] = make([]int, m)
right[i] = make([]int, m)
}
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
if grid[i][j] != '#' && i > 0 && grid[i-1][j] != '#' {
up[i][j] = up[i-1][j] + 1
}
}
}
for i := n - 1; i >= 0; i-- {
for j := 0; j < m; j++ {
if grid[i][j] != '#' && i < n-1 && grid[i+1][j] != '#' {
down[i][j] = down[i+1][j] + 1
}
}
}
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
if grid[i][j] != '#' && j > 0 && grid[i][j-1] != '#' {
left[i][j] = left[i][j-1] + 1
}
}
}
for i := 0; i < n; i++ {
for j := m - 1; j >= 0; j-- {
if grid[i][j] != '#' && j < m-1 && grid[i][j+1] != '#' {
right[i][j] = right[i][j+1] + 1
}
}
}
var k int
fmt.Fscan(reader, &k)
type Inst struct {
dir string
length int
}
instructions := make([]Inst, k)
for i := 0; i < k; i++ {
fmt.Fscan(reader, &instructions[i].dir, &instructions[i].length)
}
var result []byte
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
if grid[i][j] >= 'A' && grid[i][j] <= 'Z' {
r, c := i, j
valid := true
for _, inst := range instructions {
switch inst.dir {
case "N":
if up[r][c] < inst.length {
valid = false
} else {
r -= inst.length
}
case "S":
if down[r][c] < inst.length {
valid = false
} else {
r += inst.length
}
case "W":
if left[r][c] < inst.length {
valid = false
} else {
c -= inst.length
}
case "E":
if right[r][c] < inst.length {
valid = false
} else {
c += inst.length
}
}
if !valid {
break
}
}
if valid {
result = append(result, grid[i][j])
}
}
}
}
if len(result) == 0 {
fmt.Println("no solution")
} else {
sort.Slice(result, func(i, j int) bool { return result[i] < result[j] })
fmt.Println(string(result))
}
}
```