← Home
For problem statement at 0-999/400-499/470-479/478/problemE.txt this is a correct solution, but verifier at 0-999/400-499/470-479/478/verifierE.go ends with  can you fix the verifier? ```go
package main

import (
	"bufio"
	"fmt"
	"os"
)

const LIMIT = 100000000000000 // 10^14

func main() {
	var n, k int64
	// Fast IO
	reader := bufio.NewReader(os.Stdin)
	fmt.Fscan(reader, &n, &k)

	// Threshold for switching between Iteration and DP
	// N=250000 uses ~120MB RAM and runs reasonably fast with vectorized DP
	threshold := int64(250000)

	if n > threshold {
		solveIteration(n, k)
	} else {
		solveDP(n, k)
	}
}

func solveIteration(n, k int64) {
	cnt := int64(0)
	var digits [16]int8

	for r := n; r <= LIMIT; r += n {
		// Check wavy
		val := r
		idx := 0
		for val > 0 {
			digits[idx] = int8(val % 10)
			val /= 10
			idx++
		}
		
		isWavy := true
		if idx > 1 {
			// Check first pair
			d1 := digits[idx-1]
			d2 := digits[idx-2]
			if d1 == d2 {
				isWavy = false
			} else {
				lastDiff := int8(0)
				if d2 > d1 {
					lastDiff = 1
				} else {
					lastDiff = -1
				}
				
				for i := idx - 2; i > 0; i-- {
					curr := digits[i]
					next := digits[i-1]
					if curr == next {
						isWavy = false; break
					}
					diff := int8(0)
					if next > curr {
						diff = 1
					} else {
						diff = -1
					}
					if diff == lastDiff {
						isWavy = false; break
					}
					lastDiff = diff
				}
			}
		}

		if isWavy {
			cnt++
			if cnt == k {
				fmt.Println(r)
				return
			}
		}
	}
	fmt.Println("-1")
}

// DP State: dp[last_digit][slope_type][remainder]
// slope_type: 0 -> peak (last > next), 1 -> valley (last < next), 2 -> len 1
func solveDP(n, k int64) {
	// Precompute powers of 10 mod n
	pow10 := make([]int64, 16)
	pow10[0] = 1 % n
	for i := 1; i < 16; i++ {
		pow10[i] = (pow10[i-1] * 10) % n
	}

	// Buffers for DP
	// Using flat arrays for cache friendliness
	// size = 10 * 3 * n
	sz := int(n)
	type Layer struct {
		data []int64 
	}
	newLayer := func() Layer {
		return Layer{data: make([]int64, 30*sz)}
	}
	
	// Helper to access data: [d][type][rem]
	// index = (d * 3 + type) * sz + rem
	
	dp := newLayer()
	nextDp := newLayer()

	// 1. Find the target length
	targetLen := -1
	
	// Initialize len 1
	for d := 0; d <= 9; d++ {
		rem := int64(d) % n
		// type 2 for length 1
		idx := (d*3 + 2) * sz + int(rem)
		dp.data[idx] = 1
	}

	for l := 1; l <= 14; l++ {
		// Count total valid for this length
		// Must start with d != 0 unless length is 1 (but wavy numbers > 0)
		total := int64(0)
		for d := 1; d <= 9; d++ {
			// remainder must be 0
			// sum over all types
			for t := 0; t < 3; t++ {
				idx := (d*3 + t) * sz // rem 0
				total += dp.data[idx]
			}
		}
		
		if k <= total {
			targetLen = l
			break
		}
		k -= total
		
		if l == 14 {
			break
		}

		// Transition to l+1
		// Clear nextDp
		for i := range nextDp.data {
			nextDp.data[i] = 0
		}

		// Compute nextDp from dp
		// dp represents suffixes of length l
		// We prepend a digit `newD`
		// new_rem = (newD * 10^l + old_rem) % n
		// shift = (newD * 10^l) % n
		
		shiftBase := pow10[l]
		
		for newD := 0; newD <= 9; newD++ {
			shift := (int64(newD) * shiftBase) % n
			s := int(shift)
			
			for oldD := 0; oldD <= 9; oldD++ {
				if newD == oldD { continue }
				
				// Determine required slope of oldD
				// If newD < oldD: oldD is a peak relative to newD.
				// But we need oldD's relation to ITS successor.
				// The sequence is newD, oldD, next...
				// If newD < oldD, then for oldD to be a peak, we must have oldD > next.
				// So we need state 0 (peak) from oldD. 
				// State 2 (len 1) is compatible with both.
				
				// Target state for newD
				// If newD < oldD: newD is valley relative to oldD -> state 1
				// If newD > oldD: newD is peak relative to oldD -> state 0
				
				var targetState int
				if newD < oldD {
					targetState = 1 // Valley
				} else {
					targetState = 0 // Peak
				}
				
				// Which source states are valid?
				// If newD < oldD (valley), we need oldD > next (peak) -> srcState 0 or 2
				// If newD > oldD (peak), we need oldD < next (valley) -> srcState 1 or 2

				destOffset := (newD*3 + targetState) * sz
				
				if newD < oldD {
					// Need src 0 or 2
					srcOffset0 := (oldD*3 + 0) * sz
					srcOffset2 := (oldD*3 + 2) * sz
					addToDest(nextDp.data, dp.data, destOffset, srcOffset0, s, sz)
					addToDest(nextDp.data, dp.data, destOffset, srcOffset2, s, sz)
				} else {
					// Need src 1 or 2
					srcOffset1 := (oldD*3 + 1) * sz
					srcOffset2 := (oldD*3 + 2) * sz
					addToDest(nextDp.data, dp.data, destOffset, srcOffset1, s, sz)
					addToDest(nextDp.data, dp.data, destOffset, srcOffset2, s, sz)
				}
			}
		}
		// Swap
		dp, nextDp = nextDp, dp
	}

	if targetLen == -1 {
		fmt.Println("-1")
		return
	}

	// 2. Reconstruct the number
	// We know the length is targetLen
	// We iterate positions from 1 to targetLen
	
	result := make([]int, targetLen)
	currentRem := int64(0)
	lastDigit := -1
	// Slope is the relation between lastDigit and the one before it.
	// But here we need to track constraint for the NEXT digit we pick.
	// 0: must be < lastDigit
	// 1: must be > lastDigit
	// -1: Any (first digit)
	requiredSlope := -1 
	
	// Helper to re-run DP up to length L
	// This is needed because `dp` currently holds data for length 1..targetLen but mixed or overwritten
	// We need specific lengths.
	// To avoid O(L^2) full recompute, we can use the logic that we just need specific lookups.
	// However, memory is limited, so we compute on the fly.
	// Since L is small (14), recomputing is cheap.
	
	for pos := 1; pos <= targetLen; pos++ {
		remLen := targetLen - pos
		
		// Run DP to get table for remLen
		// If remLen == 0, check if we are done
		
		// Fill table for length remLen
		// We can reuse the buffers.
		// Re-initialize for length 1, run up to remLen
		
		// If remLen == 0, we just need to satisfy remainder 0.
		// But loop structure is to pick digit.
		// Digit picking happens at `pos`. `remLen` is digits AFTER this one.
		
		// Recompute DP for length `remLen`
		// Copy logic from above, but only up to remLen
		
		// Optimization: cache DP tables? With N=250000, 14 tables is too big (100MB * 14).
		// So we recompute.
		
		currentTable := newLayer() // Local buffer or reuse global if careful
		// Initialize len 1
		for d := 0; d <= 9; d++ {
			r := int64(d) % n
			idx := (d*3 + 2) * sz + int(r)
			currentTable.data[idx] = 1
		}
		
		nextTable := newLayer()
		
		for l := 1; l < remLen; l++ {
			// Clear nextTable
			for i := range nextTable.data { nextTable.data[i] = 0 }
			
			shiftBase := pow10[l]
			for newD := 0; newD <= 9; newD++ {
				shift := (int64(newD) * shiftBase) % n
				s := int(shift)
				for oldD := 0; oldD <= 9; oldD++ {
					if newD == oldD { continue }
					var targetState int
					if newD < oldD { targetState = 1 } else { targetState = 0 }
					destOffset := (newD*3 + targetState) * sz
					
					if newD < oldD {
						srcOffset0 := (oldD*3 + 0) * sz
						srcOffset2 := (oldD*3 + 2) * sz
						addToDest(nextTable.data, currentTable.data, destOffset, srcOffset0, s, sz)
						addToDest(nextTable.data, currentTable.data, destOffset, srcOffset2, s, sz)
					} else {
						srcOffset1 := (oldD*3 + 1) * sz
						srcOffset2 := (oldD*3 + 2) * sz
						addToDest(nextTable.data, currentTable.data, destOffset, srcOffset1, s, sz)
						addToDest(nextTable.data, currentTable.data, destOffset, srcOffset2, s, sz)
					}
				}
			}
			currentTable, nextTable = nextTable, currentTable
		}
		
		// Now currentTable holds data for suffix length `remLen`.
		// If remLen == 0, we treat it as count=1 if rem==0 else 0.
		
		foundDigit := false
		startD := 0
		if pos == 1 { startD = 1 }
		
		for d := startD; d <= 9; d++ {
			// Check wavy constraint with lastDigit
			if lastDigit != -1 {
				if d == lastDigit { continue }
				if requiredSlope == 0 && d > lastDigit { continue } // wanted smaller
				if requiredSlope == 1 && d < lastDigit { continue } // wanted larger
			}
			
			// Count valid suffixes
			count := int64(0)
			
			// We need (currentRem * 10^remLen + d * 10^(remLen-1) + suffix) % n == 0
			// Wait, the DP state for length `remLen` assumes `d` is part of it? 
			// No, `remLen` above is length of remaining suffix AFTER `d`. 
			// So total length = pos (fixed) + 1 (current `d`) + (remLen-1)?
			// My logic for remLen was: remaining digits to pick.
			// If `pos` is current being picked, then `remLen` is digits AFTER `d`.
			// So `d` is the "top" of a suffix of length `remLen + 1`.
			// But we computed DP table for length `remLen`.
			// The suffix starts with `d_next`.
			
			// Let's adjust.
			// We are picking `d` at `pos`.
			// Remaining part has length `remLen`.
			// We need remainder `req` such that (prefix_so_far * 10^remLen + suffix) % n == 0
			// prefix_so_far includes `d`.
			// `current_prefix_val` = old_currentRem * 10 + d.
			
			// Special case: remLen == 0.
			if remLen == 0 {
				val := (currentRem * 10 + int64(d)) % n
				if val == 0 {
					count = 1
				} else {
					count = 0
				}
			} else {
				// We look at DP table for length `remLen`.
				// We need a suffix starting with `next_d` that is compatible with `d`.
				// Suffix val `S`.
				// ( (currentRem * 10 + d) * 10^remLen + S ) % n == 0
				// S % n = ( - (currentRem * 10 + d) * 10^remLen ) % n
				
				prefix := (currentRem * 10 + int64(d)) % n
				reqRem := (n - (prefix * pow10[remLen]) % n) % n
				
				// Sum over valid next_d
				for nextD := 0; nextD <= 9; nextD++ {
					if nextD == d { continue }
					
					// Compatibility
					// Sequence: ... lastDigit, d, nextD ...
					// We checked lastDigit vs d.
					// Now check d vs nextD.
					// If lastDigit != -1:
					//   If d < lastDigit (valley at d), then d must be < nextD (so nextD > d).
					//   If d > lastDigit (peak at d), then d must be > nextD (so nextD < d).
					// But `d` is not yet fixed as peak/valley relative to `nextD`.
					// Wait, the wavy definition is local.
					// If lastDigit != -1:
					//    If d < lastDigit, we went down. Next must go up (nextD > d).
					//    If d > lastDigit, we went up. Next must go down (nextD < d).
					
					validNext := true
					if lastDigit != -1 {
						if d < lastDigit {
							if !(nextD > d) { validNext = false }
						} else { // d > lastDigit
							if !(nextD < d) { validNext = false }
						}
					}
					
					if validNext {
						// DP state to lookup
						// We are looking at suffix starting with `nextD`.
						// We need its relation to ITS successor.
						// If nextD > d (we went up), then nextD must go down to successor -> State 0 (peak) or 2.
						// If nextD < d (we went down), then nextD must go up to successor -> State 1 (valley) or 2.
						
						// Note: The DP state definitions:
						// 0: peak (digit > next)
						// 1: valley (digit < next)
						// 2: len 1
						
						// If nextD > d: nextD is a peak?
						// d, nextD, nextNext.
						// Since d < nextD, we need nextD > nextNext.
						// So we need state 0 or 2 for nextD.
						
						// If nextD < d: nextD is a valley?
						// d, nextD, nextNext.
						// Since d > nextD, we need nextD < nextNext.
						// So we need state 1 or 2 for nextD.
						
						idxBase := (nextD * 3) * sz + int(reqRem)
						if nextD > d {
							count += currentTable.data[idxBase + 0*sz] // State 0
							count += currentTable.data[idxBase + 2*sz] // State 2
						} else {
							count += currentTable.data[idxBase + 1*sz] // State 1
							count += currentTable.data[idxBase + 2*sz] // State 2
						}
					}
				}
			}
			
			if k <= count {
				result[pos-1] = d
				currentRem = (currentRem * 10 + int64(d)) % n
				
				// Update slope requirement for next step
				// If we just picked `d` and had `lastDigit`:
				// If d < lastDigit, next must be > d.
				// If d > lastDigit, next must be < d.
				if lastDigit != -1 {
					if d < lastDigit {
						requiredSlope = 1 // next > d
					} else {
						requiredSlope = 0 // next < d
					}
				}
				lastDigit = d
				foundDigit = true
				break
			} else {
				k -= count
			}
		}
		if !foundDigit {
			// Should not happen if logic is correct
			fmt.Println("-1")
			return
		}
	}
	
	for _, d := range result {
		fmt.Print(d)
	}
	fmt.Println()
}

func addToDest(dest []int64, src []int64, destOff, srcOff, s, sz int) {
	// dest[destOff + (i+s)%sz] += src[srcOff + i]
	// Vectorized manual loop
	
	// Slice bounds
	d := dest[destOff : destOff+sz]
	srcSl := src[srcOff : srcOff+sz]
	
	lim := sz - s
	for i := 0; i < lim; i++ {
		d[i+s] += srcSl[i]
	}
	for i := lim; i < sz; i++ {
		d[i+s-sz] += srcSl[i]
	}
}
```