```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]
}
}
```