For problem statement at 1000-1999/1700-1799/1770-1779/1773/problemH.txt this is a correct solution, but verifier at 1000-1999/1700-1799/1770-1779/1773/verifierH.go ends with case 4 failed (treasure at 0 1000000): failed to read x for query 65: EOF stderr:
exit status 1 can you fix the verifier? package main
import (
"bufio"
"fmt"
"math"
"os"
"sort"
"strings"
)
const N = 1000000
const eps = 1e-9
type IPoint struct {
x, y int
}
type FPoint struct {
x, y float64
}
func readLine(r *bufio.Reader) string {
for {
s, err := r.ReadString('\n')
if err != nil && len(s) == 0 {
os.Exit(0)
}
s = strings.TrimSpace(s)
if s != "" {
return s
}
if err != nil {
os.Exit(0)
}
}
}
func query(w *bufio.Writer, r *bufio.Reader, p IPoint) (string, bool) {
fmt.Fprintf(w, "%d %d\n", p.x, p.y)
w.Flush()
s := readLine(r)
if strings.Contains(s, "!") {
return s, true
}
return s, false
}
func dot(a, b FPoint) float64 {
return a.x*b.x + a.y*b.y
}
func area(poly []FPoint) float64 {
n := len(poly)
if n < 3 {
return 0
}
s := 0.0
for i := 0; i < n; i++ {
j := (i + 1) % n
s += poly[i].x*poly[j].y - poly[j].x*poly[i].y
}
if s < 0 {
s = -s
}
return s * 0.5
}
func bbox(poly []FPoint) (float64, float64, float64, float64) {
if len(poly) == 0 {
return 0, 0, 0, 0
}
minx, maxx := poly[0].x, poly[0].x
miny, maxy := poly[0].y, poly[0].y
for _, p := range poly {
if p.x < minx {
minx = p.x
}
if p.x > maxx {
maxx = p.x
}
if p.y < miny {
miny = p.y
}
if p.y > maxy {
maxy = p.y
}
}
return minx, maxx, miny, maxy
}
func centroid(poly []FPoint) FPoint {
n := len(poly)
if n < 3 {
minx, maxx, miny, maxy := bbox(poly)
return FPoint{(minx + maxx) * 0.5, (miny + maxy) * 0.5}
}
a2 := 0.0
cx, cy := 0.0, 0.0
for i := 0; i < n; i++ {
j := (i + 1) % n
cr := poly[i].x*poly[j].y - poly[j].x*poly[i].y
a2 += cr
cx += (poly[i].x + poly[j].x) * cr
cy += (poly[i].y + poly[j].y) * cr
}
if math.Abs(a2) < 1e-12 {
minx, maxx, miny, maxy := bbox(poly)
return FPoint{(minx + maxx) * 0.5, (miny + maxy) * 0.5}
}
return FPoint{cx / (3 * a2), cy / (3 * a2)}
}
func clip(poly []FPoint, n FPoint, c float64, keepPos bool) []FPoint {
if len(poly) == 0 {
return nil
}
res := make([]FPoint, 0, len(poly)+2)
inside := func(v float64) bool {
if keepPos {
return v >= -eps
}
return v <= eps
}
for i := 0; i < len(poly); i++ {
a := poly[i]
b := poly[(i+1)%len(poly)]
va := dot(n, a) - c
vb := dot(n, b) - c
ina := inside(va)
inb := inside(vb)
if ina && inb {
res = append(res, b)
} else if ina && !inb {
t := va / (va - vb)
res = append(res, FPoint{
a.x + (b.x-a.x)*t,
a.y + (b.y-a.y)*t,
})
} else if !ina && inb {
t := va / (va - vb)
res = append(res, FPoint{
a.x + (b.x-a.x)*t,
a.y + (b.y-a.y)*t,
})
res = append(res, b)
}
}
if len(res) >= 2 {
tmp := make([]FPoint, 0, len(res))
for i := 0; i < len(res); i++ {
j := (i + 1) % len(res)
if math.Hypot(res[i].x-res[j].x, res[i].y-res[j].y) > 1e-10 {
tmp = append(tmp, res[i])
}
}
res = tmp
}
return res
}
func pointInPoly(poly []FPoint, p IPoint) bool {
if len(poly) == 0 {
return false
}
x := float64(p.x)
y := float64(p.y)
sign := 0
for i := 0; i < len(poly); i++ {
a := poly[i]
b := poly[(i+1)%len(poly)]
cr := (b.x-a.x)*(y-a.y) - (b.y-a.y)*(x-a.x)
if math.Abs(cr) <= 1e-7 {
continue
}
if cr > 0 {
if sign < 0 {
return false
}
sign = 1
} else {
if sign > 0 {
return false
}
sign = -1
}
}
return true
}
func sqdist(a, b IPoint) int64 {
dx := int64(a.x - b.x)
dy := int64(a.y - b.y)
return dx*dx + dy*dy
}
func consistent(t IPoint, ori int, pts []IPoint, resps []string, sameLabel, labelA, labelB string) bool {
if len(pts) == 0 {
return true
}
if t == pts[0] {
return false
}
for i := 1; i < len(pts); i++ {
if t == pts[i] {
return false
}
d1 := sqdist(t, pts[i-1])
d2 := sqdist(t, pts[i])
if d1 == d2 {
if resps[i] != sameLabel {
return false
}
} else {
closer := labelA
further := labelB
if ori == 1 {
closer, further = labelB, labelA
}
if d2 < d1 {
if closer == "" || resps[i] != closer {
return false
}
} else {
if further == "" || resps[i] != further {
return false
}
}
}
}
return true
}
func enumerateCandidates(polys [2][]FPoint, pts []IPoint, resps []string, sameLabel, labelA, labelB string, limitScan int) []IPoint {
type node struct {
poly []FPoint
ori int
}
items := []node{
{polys[0], 0},
{polys[1], 1},
}
seen := map[[2]int]bool{}
ans := make([]IPoint, 0)
for _, it := range items {
if len(it.poly) == 0 {
continue
}
minx, maxx, miny, maxy := bbox(it.poly)
lx := int(math.Ceil(minx - 2.0))
rx := int(math.Floor(maxx + 2.0))
ly := int(math.Ceil(miny - 2.0))
ry := int(math.Floor(maxy + 2.0))
if lx < 0 {
lx = 0
}
if ly < 0 {
ly = 0
}
if rx > N {
rx = N
}
if ry > N {
ry = N
}
if lx > rx || ly > ry {
continue
}
areaBox := int64(rx-lx+1) * int64(ry-ly+1)
if areaBox > int64(limitScan) {
return nil
}
for x := lx; x <= rx; x++ {
for y := ly; y <= ry; y++ {
p := IPoint{x, y}
if !pointInPoly(it.poly, p) {
continue
}
if !consistent(p, it.ori, pts, resps, sameLabel, labelA, labelB) {
continue
}
k := [2]int{x, y}
if !seen[k] {
seen[k] = true
ans = append(ans, p)
}
}
}
}
sort.Slice(ans, func(i, j int) bool {
if ans[i].x != ans[j].x {
return ans[i].x < ans[j].x
}
return ans[i].y < ans[j].y
})
return ans
}
func chooseNext(cur IPoint, polys [2][]FPoint) IPoint {
P, Q := polys[0], polys[1]
areaP := area(P)
areaQ := area(Q)
cands := make([]IPoint, 0, 1024)
used := map[[2]int]bool{}
add := func(x, y int) {
if x < 0 || x > N || y < 0 || y > N {
return
}
if x == cur.x && y == cur.y {
return
}
if ((x+y)&1) == ((cur.x+cur.y)&1) {
return
}
k := [2]int{x, y}
if used[k] {
return
}
used[k] = true
cands = append(cands, IPoint{x, y})
}
grid := 20
for i := 0; i <= grid; i++ {
x := int(math.Round(float64(N) * float64(i) / float64(grid)))
for j := 0; j <= grid; j++ {
y := int(math.Round(float64(N) * float64(j) / float64(grid)))
add(x, y)
}
}
cs := []FPoint{centroid(P), centroid(Q)}
for _, poly := range polys {
if len(poly) == 0 {
continue
}
minx, maxx, miny, maxy := bbox(poly)
cs = append(cs, FPoint{(minx + maxx) * 0.5, (miny + maxy) * 0.5})
for _, v := range poly {
cs = append(cs, v)
}
}
for _, c := range cs {
rx := int(math.Round(2*c.x - float64(cur.x)))
ry := int(math.Round(2*c.y - float64(cur.y)))
for dx := -2; dx <= 2; dx++ {
for dy := -2; dy <= 2; dy++ {
add(rx+dx, ry+dy)
}
}
}
add(0, 0)
add(0, N)
add(N, 0)
add(N, N)
add(cur.x^1, cur.y)
add(cur.x, cur.y^1)
best := IPoint{(cur.x + 1) % (N + 1), cur.y}
if ((best.x+best.y)&1) == ((cur.x+cur.y)&1) {
best.y ^= 1
if best.y < 0 || best.y > N {
best.y = cur.y
best.x ^= 1
}
}
bestScore := math.Inf(1)
for _, b := range cands {
n := FPoint{float64(b.x - cur.x), float64(b.y - cur.y)}
c := (float64(b.x*b.x+b.y*b.y) - float64(cur.x*cur.x+cur.y*cur.y)) * 0.5
ap := area(clip(P, n, c, true))
aqm := area(clip(Q, n, c, false))
t1 := ap + aqm
t2 := (areaP - ap) + (areaQ - aqm)
score := math.Max(t1, t2)
if score+1e-7 < bestScore {
bestScore = score
best = b
}
}
return best
}
func updatePolys(cur, next IPoint, resp string, sameLabel, labelA string, polys *[2][]FPoint) {
if resp == sameLabel {
return
}
n := FPoint{float64(next.x - cur.x), float64(next.y - cur.y)}
c := (float64(next.x*next.x+next.y*next.y) - float64(cur.x*cur.x+cur.y*cur.y)) * 0.5
if resp == labelA {
polys[0] = clip(polys[0], n, c, true)
polys[1] = clip(polys[1], n, c, false)
} else {
polys[0] = clip(polys[0], n, c, false)
polys[1] = clip(polys[1], n, c, true)
}
}
func main() {
in := bufio.NewReaderSize(os.Stdin, 1<<20)
out := bufio.NewWriterSize(os.Stdout, 1<<20)
defer out.Flush()
square := []FPoint{{0, 0}, {float64(N), 0}, {float64(N), float64(N)}, {0, float64(N)}}
polys := [2][]FPoint{append([]FPoint{}, square...), append([]FPoint{}, square...)}
cur := IPoint{N / 2, N / 2}
resp, found := query(out, in, cur)
if found {
return
}
pts := []IPoint{cur}
resps := []string{resp}
resp, found = query(out, in, cur)
if found {
return
}
sameLabel := resp
pts = append(pts, cur)
resps = append(resps, resp)
labelA := ""
labelB := ""
queries := 2
process := func(next IPoint, resp string) {
if resp != sameLabel {
if labelA == "" {
labelA = resp
} else if resp != labelA && labelB == "" {
labelB = resp
}
updatePolys(cur, next, resp, sameLabel, labelA, &polys)
}
cur = next
pts = append(pts, next)
resps = append(resps, resp)
}
for queries < 60 {
cands := enumerateCandidates(polys, pts, resps, sameLabel, labelA, labelB, 50000)
if len(cands) > 0 && len(cands) <= 64-queries {
for _, p := range cands {
resp, found = query(out, in, p)
queries++
if found {
return
}
process(p, resp)
if queries >= 64 {
return
}
}
continue
}
next := chooseNext(cur, polys)
resp, found = query(out, in, next)
queries++
if found {
return
}
process(next, resp)
}
cands := enumerateCandidates(polys, pts, resps, sameLabel, labelA, labelB, 300000)
if len(cands) == 0 {
minx0, maxx0, miny0, maxy0 := bbox(polys[0])
minx1, maxx1, miny1, maxy1 := bbox(polys[1])
guess := []IPoint{
{int(math.Round((minx0 + maxx0) * 0.5)), int(math.Round((miny0 + maxy0) * 0.5))},
{int(math.Round((minx1 + maxx1) * 0.5)), int(math.Round((miny1 + maxy1) * 0.5))},
{0, 0},
{0, N},
{N, 0},
{N, N},
}
used := map[[2]int]bool{}
for _, p := range guess {
if p.x < 0 {
p.x = 0
}
if p.x > N {
p.x = N
}
if p.y < 0 {
p.y = 0
}
if p.y > N {
p.y = N
}
k := [2]int{p.x, p.y}
if used[k] {
continue
}
used[k] = true
cands = append(cands, p)
}
}
for _, p := range cands {
if queries >= 64 {
return
}
_, found = query(out, in, p)
queries++
if found {
return
}
}
}