package main
import (
"bufio"
"io"
"os"
"strconv"
)
type FastScanner struct {
data []byte
idx int
}
func (fs *FastScanner) skip() {
for fs.idx < len(fs.data) && fs.data[fs.idx] <= ' ' {
fs.idx++
}
}
func (fs *FastScanner) nextInt() int {
fs.skip()
v := 0
for fs.idx < len(fs.data) {
c := fs.data[fs.idx]
if c < '0' || c > '9' {
break
}
v = v*10 + int(c-'0')
fs.idx++
}
return v
}
func (fs *FastScanner) nextToken() []byte {
fs.skip()
start := fs.idx
for fs.idx < len(fs.data) && fs.data[fs.idx] > ' ' {
fs.idx++
}
return fs.data[start:fs.idx]
}
func main() {
data, _ := io.ReadAll(os.Stdin)
fs := FastScanner{data: data}
n := fs.nextInt()
a := make([]int32, n)
maxV := 1
for i := 0; i < n; i++ {
v := fs.nextInt()
a[i] = int32(v)
if v > maxV {
maxV = v
}
}
tok := fs.nextToken()
b := make([]byte, len(tok))
copy(b, tok)
data = nil
fs.data = nil
if maxV < 2 {
ans := int64(n) * int64(n+1) / 2
out := bufio.NewWriterSize(os.Stdout, 1<<20)
out.WriteString(strconv.FormatInt(ans, 10))
out.Flush()
return
}
spf := make([]int32, maxV+1)
primes := make([]int, 0, 80000)
for i := 2; i <= maxV; i++ {
if spf[i] == 0 {
spf[i] = int32(i)
primes = append(primes, i)
}
si := int(spf[i])
for _, p := range primes {
v := p * i
if v > maxV || p > si {
break
}
spf[v] = int32(p)
}
}
primeID := make([]int32, maxV+1)
counts := make([]int32, 0, 80000)
for i := 0; i < n; i++ {
x := int(a[i])
for x > 1 {
p := int(spf[x])
for x > 1 && int(spf[x]) == p {
x /= p
}
id1 := primeID[p]
if id1 == 0 {
counts = append(counts, 0)
id1 = int32(len(counts))
primeID[p] = id1
}
counts[id1-1]++
}
}
P := len(counts)
if P == 0 {
ans := int64(n) * int64(n+1) / 2
out := bufio.NewWriterSize(os.Stdout, 1<<20)
out.WriteString(strconv.FormatInt(ans, 10))
out.Flush()
return
}
occOffset := make([]int32, P+1)
maxCount := 0
for i := 0; i < P; i++ {
occOffset[i+1] = occOffset[i] + counts[i]
if int(counts[i]) > maxCount {
maxCount = int(counts[i])
}
}
M := int(occOffset[P])
positions := make([]int32, M)
weights := make([]int8, M)
cursor := make([]int32, P)
copy(cursor, occOffset[:P])
for i := 0; i < n; i++ {
x := int(a[i])
if x == 1 {
continue
}
s := int8(1)
if b[i] == '/' {
s = -1
}
for x > 1 {
p := int(spf[x])
e := 0
for x > 1 && int(spf[x]) == p {
x /= p
e++
}
id := int(primeID[p] - 1)
idx := cursor[id]
positions[idx] = int32(i + 1)
weights[idx] = int8(e) * s
cursor[id] = idx + 1
}
}
b = nil
badOffset := make([]int32, P+1)
for i := 0; i < P; i++ {
badOffset[i+1] = badOffset[i] + counts[i] + 1
}
badPos := make([]int32, int(badOffset[P]))
tempCum := make([]int32, maxCount+1)
tempStack := make([]int, maxCount+1)
for id := 0; id < P; id++ {
start := int(occOffset[id])
m := int(counts[id])
bstart := int(badOffset[id])
cum := tempCum[:m+1]
cum[0] = 0
for j := 1; j <= m; j++ {
cum[j] = cum[j-1] + int32(weights[start+j-1])
}
top := 0
for i := m; i >= 0; i-- {
ci := cum[i]
for top > 0 && cum[tempStack[top-1]] >= ci {
top--
}
if top == 0 {
badPos[bstart+i] = int32(n + 1)
} else {
badPos[bstart+i] = positions[start+tempStack[top-1]-1]
}
tempStack[top] = i
top++
}
}
size := 1
for size < P {
size <<= 1
}
inf := int32(n + 1)
seg := make([]int32, size<<1)
for i := range seg {
seg[i] = inf
}
for i := 0; i < P; i++ {
seg[size+i] = badPos[int(badOffset[i])]
}
for i := size - 1; i >= 1; i-- {
left := seg[i<<1]
right := seg[i<<1|1]
if left < right {
seg[i] = left
} else {
seg[i] = right
}
}
currentIdx := cursor
for i := 0; i < P; i++ {
currentIdx[i] = 0
}
var ans int64
for l := 1; l <= n; l++ {
ans += int64(seg[1] - int32(l))
x := int(a[l-1])
for x > 1 {
p := int(spf[x])
for x > 1 && int(spf[x]) == p {
x /= p
}
id := int(primeID[p] - 1)
currentIdx[id]++
val := badPos[int(badOffset[id]+currentIdx[id])]
leaf := size + id
if seg[leaf] != val {
seg[leaf] = val
for pos := leaf >> 1; pos > 0; pos >>= 1 {
nv := seg[pos<<1]
if seg[pos<<1|1] < nv {
nv = seg[pos<<1|1]
}
if seg[pos] == nv {
break
}
seg[pos] = nv
}
}
}
}
out := bufio.NewWriterSize(os.Stdout, 1<<20)
out.WriteString(strconv.FormatInt(ans, 10))
out.Flush()
}