← Home
For problem statement at 1000-1999/1500-1599/1530-1539/1534/problemF2.txt this is a correct solution, but verifier at 1000-1999/1500-1599/1530-1539/1534/verifierF2.go ends with All tests passed can you fix the verifier? package main

import (
	"bufio"
	"fmt"
	"io"
	"math/bits"
	"os"
)

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()
	val := 0
	for fs.idx < len(fs.data) && fs.data[fs.idx] > ' ' {
		val = val*10 + int(fs.data[fs.idx]-'0')
		fs.idx++
	}
	return val
}

func (fs *FastScanner) nextBytes() []byte {
	fs.skip()
	start := fs.idx
	for fs.idx < len(fs.data) && fs.data[fs.idx] > ' ' {
		fs.idx++
	}
	return fs.data[start:fs.idx]
}

type Pair struct {
	dp  int
	far int
}

type MinHeap struct {
	a []Pair
}

func less(x, y Pair) bool {
	if x.dp != y.dp {
		return x.dp < y.dp
	}
	return x.far < y.far
}

func (h *MinHeap) Push(x Pair) {
	h.a = append(h.a, x)
	i := len(h.a) - 1
	for i > 0 {
		p := (i - 1) >> 1
		if !less(h.a[i], h.a[p]) {
			break
		}
		h.a[i], h.a[p] = h.a[p], h.a[i]
		i = p
	}
}

func (h *MinHeap) Pop() Pair {
	res := h.a[0]
	last := h.a[len(h.a)-1]
	h.a = h.a[:len(h.a)-1]
	if len(h.a) == 0 {
		return res
	}
	h.a[0] = last
	i := 0
	for {
		l := i*2 + 1
		if l >= len(h.a) {
			break
		}
		r := l + 1
		j := l
		if r < len(h.a) && less(h.a[r], h.a[l]) {
			j = r
		}
		if !less(h.a[j], h.a[i]) {
			break
		}
		h.a[i], h.a[j] = h.a[j], h.a[i]
		i = j
	}
	return res
}

var topState []int32
var upR [][]int32
var upL [][]int32
var runStart []int
var capRow []int

func coverLeft(seed, target int) bool {
	if seed == target {
		return true
	}
	s := int(topState[seed])
	d := target - seed
	k := 0
	for d > 0 {
		if d&1 != 0 {
			s = int(upR[k][s])
			if s == 0 {
				return false
			}
		}
		d >>= 1
		k++
	}
	return runStart[s] <= capRow[target]
}

func coverRight(seed, target int) bool {
	if seed == target {
		return true
	}
	s := int(topState[seed])
	d := seed - target
	k := 0
	for d > 0 {
		if d&1 != 0 {
			s = int(upL[k][s])
			if s == 0 {
				return false
			}
		}
		d >>= 1
		k++
	}
	return runStart[s] <= capRow[target]
}

func main() {
	data, _ := io.ReadAll(os.Stdin)
	fs := FastScanner{data: data}

	n := fs.nextInt()
	m := fs.nextInt()

	cols := make([][]int, m+1)
	for r := 1; r <= n; r++ {
		row := fs.nextBytes()
		for c, ch := range row {
			if ch == '#' {
				cols[c+1] = append(cols[c+1], r)
			}
		}
	}

	a := make([]int, m+1)
	for i := 1; i <= m; i++ {
		a[i] = fs.nextInt()
	}

	count := make([]int, m+1)
	capRow = make([]int, m+1)
	req := make([]bool, m+1)
	colRunStart := make([]int, m+1)
	colRunCnt := make([]int, m+1)
	topState = make([]int32, m+1)

	runStart = []int{0}
	runEnd := []int{0}

	for c := 1; c <= m; c++ {
		occ := cols[c]
		cnt := len(occ)
		count[c] = cnt
		if a[c] > 0 {
			req[c] = true
			capRow[c] = occ[cnt-a[c]]
		}
		if cnt > 0 {
			colRunStart[c] = len(runStart)
			for i := 0; i < cnt; {
				j := i + 1
				for j < cnt && occ[j] == occ[j-1]+1 {
					j++
				}
				runStart = append(runStart, occ[i])
				runEnd = append(runEnd, occ[j-1])
				i = j
			}
			colRunCnt[c] = len(runStart) - colRunStart[c]
			topState[c] = int32(colRunStart[c])
		}
	}

	totalRuns := len(runStart) - 1
	nextRight := make([]int32, totalRuns+1)
	nextLeft := make([]int32, totalRuns+1)

	for c := 1; c < m; c++ {
		if count[c] == 0 || count[c+1] == 0 {
			continue
		}
		a0 := colRunStart[c]
		ac := colRunCnt[c]
		b0 := colRunStart[c+1]
		bc := colRunCnt[c+1]

		qb := 0
		for ia := 0; ia < ac; ia++ {
			idA := a0 + ia
			s := runStart[idA]
			for qb < bc && runEnd[b0+qb] < s {
				qb++
			}
			if qb < bc {
				nextRight[idA] = int32(b0 + qb)
			}
		}

		qa := 0
		for ib := 0; ib < bc; ib++ {
			idB := b0 + ib
			s := runStart[idB]
			for qa < ac && runEnd[a0+qa] < s {
				qa++
			}
			if qa < ac {
				nextLeft[idB] = int32(a0 + qa)
			}
		}
	}

	logM := bits.Len(uint(m))
	if logM == 0 {
		logM = 1
	}
	upR = make([][]int32, logM)
	upL = make([][]int32, logM)
	upR[0] = nextRight
	upL[0] = nextLeft

	for k := 1; k < logM; k++ {
		prevR := upR[k-1]
		curR := make([]int32, totalRuns+1)
		for s := 1; s <= totalRuns; s++ {
			x := prevR[s]
			if x != 0 {
				curR[s] = prevR[int(x)]
			}
		}
		upR[k] = curR

		prevL := upL[k-1]
		curL := make([]int32, totalRuns+1)
		for s := 1; s <= totalRuns; s++ {
			x := prevL[s]
			if x != 0 {
				curL[s] = prevL[int(x)]
			}
		}
		upL[k] = curL
	}

	Lcov := make([]int, m+1)
	Rcov := make([]int, m+1)
	far := make([]int, m+1)
	dp := make([]int, m+1)
	prefixCover := make([]bool, m+1)
	suffixCover := make([]bool, m+1)

	const INF = int(1e9)
	answer := 0
	heap := MinHeap{}

	for c := 1; c <= m; {
		if count[c] == 0 {
			c++
			continue
		}
		L := c
		hasReqSeg := false
		for c <= m && count[c] > 0 {
			if req[c] {
				hasReqSeg = true
			}
			c++
		}
		R := c - 1

		if !hasReqSeg {
			continue
		}

		for i := L; i <= R; i++ {
			if !req[i] {
				continue
			}

			lo, hi := L, i
			for lo < hi {
				mid := (lo + hi) >> 1
				if coverLeft(mid, i) {
					hi = mid
				} else {
					lo = mid + 1
				}
			}
			Lcov[i] = lo

			lo, hi = i, R
			for lo < hi {
				mid := (lo + hi + 1) >> 1
				if coverRight(mid, i) {
					lo = mid
				} else {
					hi = mid - 1
				}
			}
			Rcov[i] = lo
		}

		bucketMin := make([]int, R-L+1)
		for i := range bucketMin {
			bucketMin[i] = R + 1
		}
		for i := L; i <= R; i++ {
			if req[i] {
				idx := Lcov[i] - L
				if Rcov[i] < bucketMin[idx] {
					bucketMin[idx] = Rcov[i]
				}
			}
		}

		activeMin := R + 1
		for l := R; l >= L; l-- {
			if l < R {
				v := bucketMin[l+1-L]
				if v < activeMin {
					activeMin = v
				}
			}
			if activeMin <= R {
				far[l] = activeMin
			} else {
				far[l] = R
			}
		}

		minR := R
		hasReq := false
		for r := L; r <= R; r++ {
			prefixCover[r] = !hasReq || r <= minR
			if req[r] {
				if !hasReq || Rcov[r] < minR {
					minR = Rcov[r]
				}
				hasReq = true
			}
		}

		maxL := L
		hasReq = false
		for l := R; l >= L; l-- {
			suffixCover[l] = !hasReq || l >= maxL
			if req[l] {
				if !hasReq || Lcov[l] > maxL {
					maxL = Lcov[l]
				}
				hasReq = true
			}
		}

		heap.a = heap.a[:0]
		ansSeg := INF
		for r := L; r <= R; r++ {
			for len(heap.a) > 0 && heap.a[0].far < r {
				heap.Pop()
			}
			best := INF
			if prefixCover[r] {
				best = 1
			}
			if len(heap.a) > 0 {
				cand := heap.a[0].dp + 1
				if cand < best {
					best = cand
				}
			}
			dp[r] = best
			if suffixCover[r] && best < ansSeg {
				ansSeg = best
			}
			if best < INF && r < R {
				heap.Push(Pair{dp: best, far: far[r]})
			}
		}

		answer += ansSeg
	}

	out := bufio.NewWriterSize(os.Stdout, 1<<20)
	fmt.Fprintln(out, answer)
	out.Flush()
}