import java.io.*
import java.util.*

class Solution : Runnable {
    override fun run() {
        solve()
    }

    fun start() {
        Thread(null, Solution(), "whatever", (1 shl 27).toLong()).start()
    }
}

fun main(args: Array<String>) {
    Solution().start()
}

class IO {
    companion object {

        private val reader: InputReader
        private val writer: OutputWriter

        init {
            if (System.getProperty("ONLINE_JUDGE") == null) {
                reader = InputReader(FileInputStream("/Users/300041735/competitiveProgramming/src/codeforces/in.txt"))
                writer = OutputWriter(FileOutputStream("/Users/300041735/competitiveProgramming/src/codeforces/out.txt"))
            } else {
                reader = InputReader(System.`in`)
                writer = OutputWriter(System.`out`)
            }
        }

        private fun readMultipleInts(count: Int): List<Int> {
            val map = mutableListOf<Int>()
            repeat(count) {
                map.add(reader.readInt())
            }
            return map
        }

        fun readInt() = reader.readInt()
        fun readLong() = reader.readLong()
        fun readTwoInts() = readMultipleInts(2)
        fun readThreeInts() = readMultipleInts(3)
        fun readFourInts() = readMultipleInts(4)
        fun readFiveInts() = readMultipleInts(5)
        fun readSixInts() = readMultipleInts(6)
        fun readString() = reader.readString()
        fun readTree(n: Int): MutableMap<Int, MutableList<Int>> {
            val graph = mutableMapOf<Int, MutableList<Int>>()
            repeat(n - 1) {
                val u = reader.readInt()
                val v = reader.readInt()
                if (!graph.containsKey(u)) graph[u] = mutableListOf()
                if (!graph.containsKey(v)) graph[v] = mutableListOf()
                graph[u]!!.add(v)
                graph[v]!!.add(u)
            }
            return graph
        }

        fun readIntArray(n: Int): IntArray {
            return IntArray(n) { readInt() }
        }

        fun readLongArray(n: Int): Array<Long> {
            return Array(n) { readLong() }
        }

        fun write(obj: Any) {
            writer.printLine(obj)
        }

        fun flushOutput() {
            writer.flush()
        }

        fun closeOutput() {
            writer.close()
        }
    }
}

class MATH {
    companion object {

        val mod = 1000000007
        var ispre = false

        val factMod = Array(300002) { 1 }

        fun pre() {
            for (i in 2 until 300001) {
                factMod[i] = ((factMod[i - 1] * i.toLong()) % MATH.mod).toInt()
            }
        }

        fun gcd(a: Int, b: Int): Int {
            if (b == 0)
                return a
            return gcd(b, a % b)
        }

        fun gcd(a: Long, b: Long): Long {
            if (b == 0L)
                return a
            return gcd(b, a % b)
        }

        fun inverseMod(a: Int): Int {
            return powMod(a, mod - 2)
        }

        fun powMod(a: Int, b: Int): Int {
            //calculate a to the power b mod m
            if (b == 0) return 1
            return if (b % 2 == 1) {
                prodMod(a, powMod(a, b - 1))
            } else {
                val p = powMod(a, b / 2)
                prodMod(p, p)
            }
        }

        fun ncr(n: Int, r: Int): Int {
            if (!ispre) pre(); ispre = true
            return ((factMod[n].toLong() * inverseMod(((factMod[r].toLong() * factMod[n - r]) % mod).toInt())) % mod).toInt()
        }

        fun prodMod(val1: Int, val2: Int): Int {
            return ((val1.toLong() * val2) % mod).toInt()
        }

    }
}

fun solve() {

    val n = IO.readInt()
    val m = IO.readInt()
    var k = IO.readLong()

    k = n*m.toLong() - k + 1

    //loop over the ans
    var ansL = 0L
    var ansH = n*m.toLong()
    while (ansH - ansL > 1){
        //find the largest ans such that numbers greater than it are >= k
        val mid = (ansL + ansH)/2
        val count = getCount(n, m , mid)   //how many numbers are strictly greater than this number
        if (count >= k){
            //we can still go higher
            ansL = mid
        }else{
            ansH = mid - 1
        }
    }

    val count = getCount(n, m , ansH)
    if (count >= k){
        IO.write(ansH + 1)
    }else{
        IO.write(ansL + 1)
    }

    IO.flushOutput()
    IO.closeOutput()
}

fun getCount(n : Int, m : Int, search : Long) : Long{
    var count = 0L
    for(i in 1 until n + 1){
        //over each of the row
        //i*j  find the smallest j such that i*j > search -> ceil(search/i)
        val ans = (search + i )/i
        if (ans <= m) {
            count += m - ans + 1
        }
    }
    return count
}

fun isBitSet(num : Long, i : Int) : Boolean{
    return  (num.and(1L.shl(i)) > 0)
}

data class Graph(val edges: MutableMap<Int, MutableList<Int>>)

class MinSegmentTree(
        input: Array<Int>
) {
    private val tree: Array<Int>
    private val lazy: Array<Int>

    constructor(size: Int) : this(Array(size) { Int.MAX_VALUE })

    init {
        val size = nextPowerOfTwo(input.size)
        tree = Array(2 * size) { Int.MAX_VALUE }
        lazy = Array(2 * size) { Int.MAX_VALUE }
        for (i in 0 until input.size) {
            tree[i + size] = input[i]
        }
        for (i in (size - 1) downTo 1) {
            tree[i] = Math.min(tree[leftChild(i)], tree[rightChild(i)])
        }
    }

    private fun updateTree(lowerRange: Int, upperRange: Int, lowerBound: Int, upperBound: Int, index: Int, value: Int) {
        updateLazyNode(index, lowerBound, upperBound, lazy[index])
        if (noOverlap(lowerRange, upperRange, lowerBound, upperBound)) return
        else if (completeOverlap(lowerRange, upperRange, lowerBound, upperBound)) updateLazyNode(index, lowerBound, upperBound, value)
        else {
            updateTree(lowerRange, upperRange, lowerBound, midIndex(lowerBound, upperBound), leftChild(index), value)
            updateTree(lowerRange, upperRange, midIndex(lowerBound, upperBound) + 1, upperBound, rightChild(index), value)
            tree[index] = Math.min(tree[leftChild(index)], tree[rightChild(index)])
        }
    }

    private fun queryTree(lowerRange: Int, upperRange: Int, lowerBound: Int, upperBound: Int, index: Int): Int {
        updateLazyNode(index, lowerBound, upperBound, lazy[index])
        if (noOverlap(lowerRange, upperRange, lowerBound, upperBound)) return Int.MAX_VALUE
        else if (completeOverlap(lowerRange, upperRange, lowerBound, upperBound)) return tree[index]
        else {
            return Math.min(queryTree(lowerRange, upperRange, lowerBound, midIndex(lowerBound, upperBound), leftChild(index)),
                    queryTree(lowerRange, upperRange, midIndex(lowerBound, upperBound) + 1, upperBound, rightChild(index)))
        }
    }

    private fun updateLazyNode(index: Int, lowerBound: Int, upperBound: Int, delta: Int) {
        tree[index] += delta
        if (lowerBound != upperBound) {
            lazy[leftChild(index)] += delta
            lazy[rightChild(index)] += delta
        }
        lazy[index] = 0
    }

    fun getElements(N: Int): List<Int> {
        return tree.copyOfRange(tree.size / 2, tree.size / 2 + N).asList()
    }

    fun update(lowerRange: Int, upperRange: Int, value: Int) {
        updateTree(lowerRange, upperRange, 1, lazy.size / 2, 1, value)
    }

    fun query(lowerRange: Int, upperRange: Int): Int {
        return queryTree(lowerRange, upperRange, 1, lazy.size / 2, 1)
    }

    private fun noOverlap(l: Int, u: Int, lb: Int, ub: Int): Boolean = (lb > u || ub < l)

    private fun completeOverlap(l: Int, u: Int, lb: Int, ub: Int): Boolean = (lb >= l && ub <= u)

    private fun nextPowerOfTwo(num: Int): Int {
        var exponent = 2
        while (true) {
            if (exponent >= num) {
                return exponent
            }
            exponent *= 2
        }
    }

    private fun midIndex(l: Int, r: Int) = (l + r) / 2
    private fun parent(i: Int) = i / 2
    private fun leftChild(i: Int) = 2 * i
    private fun rightChild(i: Int) = 2 * i + 1

}

class InputReader(private val stream: InputStream) {
    private val buf = ByteArray(1024)
    private var curChar: Int = 0
    private var numChars: Int = 0
    private val filter: SpaceCharFilter? = null

    fun read(): Int {
        if (numChars == -1)
            throw InputMismatchException()
        if (curChar >= numChars) {
            curChar = 0
            try {
                numChars = stream.read(buf)
            } catch (e: IOException) {
                throw InputMismatchException()
            }

            if (numChars <= 0)
                return -1
        }
        return buf[curChar++].toInt()
    }

    fun readInt(): Int {
        var c = read()
        while (isSpaceChar(c))
            c = read()
        var sgn = 1
        if (c == '-'.toInt()) {
            sgn = -1
            c = read()
        }
        var res = 0
        do {
            if (c < '0'.toInt() || c > '9'.toInt())
                throw InputMismatchException()
            res *= 10
            res += c - '0'.toInt()
            c = read()
        } while (!isSpaceChar(c))
        return res * sgn
    }

    fun readLong(): Long {
        var c = read()
        while (isSpaceChar(c)) {
            c = read()
        }
        var sgn: Long = 1
        if (c == '-'.toInt()) {
            sgn = -1
            c = read()
        }
        var number: Long = 0
        do {
            number *= 10L
            number += (c - '0'.toInt()).toLong()
            c = read()
        } while (!isSpaceChar(c))
        return number * sgn
    }

    fun readString(): String {
        var c = read()
        while (isSpaceChar(c))
            c = read()
        val res = StringBuilder()
        do {
            res.appendCodePoint(c)
            c = read()
        } while (!isSpaceChar(c))
        return res.toString()
    }

    fun isSpaceChar(c: Int): Boolean {
        return filter?.isSpaceChar(c)
                ?: (c == ' '.toInt() || c == '\n'.toInt() || c == '\r'.toInt() || c == '\t'.toInt() || c == -1)
    }

    operator fun next(): String {
        return readString()
    }

    interface SpaceCharFilter {
        fun isSpaceChar(ch: Int): Boolean
    }
}

class OutputWriter {
    private val writer: PrintWriter

    constructor(outputStream: OutputStream) {
        writer = PrintWriter(BufferedWriter(OutputStreamWriter(outputStream)))
    }

    constructor(writer: Writer) {
        this.writer = PrintWriter(writer)
    }

    fun print(vararg objects: Any) {
        for (i in objects.indices) {
            if (i != 0)
                writer.print(' ')
            writer.print(objects[i])
        }
    }

    fun printLine(vararg objects: Any) {
        print(*objects)
        writer.println()
    }

    fun close() {
        writer.close()
    }

    fun flush() {
        writer.flush()
    }

}

class DinitzMaxFlowSolver(val n: Int, val s: Int, val t: Int, val graph: MutableMap<Int, MutableList<Edge>>, val edgeMap: MutableMap<Pair<Int, Int>, Edge>) {

    private val level = IntArray(n + 1) { -1 }  //storing levels of each vertex in level graph
    var maxFlow = 0L

    init {
        solve()
    }

    fun solve() {
        val next = IntArray(n + 1) { 0 }
        while (bfs()) {
            Arrays.fill(next, 0)
            var flow = 0L
            do {
                maxFlow += flow
                flow = dfs(s, next, Long.MAX_VALUE)
            } while (flow != 0L)
        }
    }

    private fun dfs(at: Int, next: IntArray, flow: Long): Long {
        if (at == t) return flow
        var size = 0
        if (graph.containsKey(at)) size = graph[at]!!.size
        while (next[at] < size) {
            val edge = graph[at]!!.get(next[at])
            if (edge.remainingCapacity() > 0 && level[edge.to] == level[at] + 1) {
                val bottleNeck = dfs(edge.to, next, Math.min(flow, edge.remainingCapacity()))
                if (bottleNeck > 0) {
                    edgeMap[Pair(edge.from, edge.to)]!!.flow += bottleNeck
                    edgeMap[Pair(edge.to, edge.from)]!!.flow -= bottleNeck
                    return bottleNeck
                }
            }
            next[at]++
        }
        return 0
    }

    private fun bfs(): Boolean {
        Arrays.fill(level, -1)
        val curLevel = ArrayDeque<Int>()
        curLevel.add(s)
        level[s] = 0

        while (curLevel.isNotEmpty()) {
            val top = curLevel.poll()
            if (graph.containsKey(top)) {
                graph[top]!!.forEach {
                    if (it.remainingCapacity() > 0 && level[it.to] == -1) {
                        level[it.to] = level[top] + 1
                        curLevel.offer(it.to)
                    }
                }
            }
        }
        return level[t] != -1
    }

}

class Edge(val from: Int, val to: Int, val capacity: Long) {
    var flow = 0L
    fun remainingCapacity(): Long {
        return capacity - flow
    }
}


import java.io.*
import java.util.*

fun <T : Comparable<T>> max(a: T, b: T): T = if (b > a) b else a
fun <T : Comparable<T>> min(a: T, b: T): T = if (b < a) b else a
fun Number.isEven(): Boolean = if (this.toInt() and 1 == 0) true else false
fun Number.isOdd (): Boolean = !this.isEven()

inline fun getVal(num: Long, rows: Long, cols: Long): Long {
    var res: Long = 0
    for (i in 1..min(num, rows)) {
        res += min(cols, num / i)
    }
    return res
}

fun main(args: Array<String>) {
    if (args.isNotEmpty()) System.setIn(FileInputStream(args[0]))
    val br = BufferedReader(InputStreamReader(System.`in`))
    val bw = BufferedWriter(OutputStreamWriter(System.out))

    val st = StringTokenizer(br.readLine())
    val on = st.nextToken().toLong()
    val om = st.nextToken().toLong()
    val k = st.nextToken().toLong()
    val n = min(on, om); val m = max(on, om)
    var lo = 1L; var hi: Long = n * m
    while (lo <= hi) {
        val mid = (lo + hi) ushr 1
        if (k <= getVal(mid, n, m)) hi = mid - 1
        else lo = mid + 1
    }
/*
    outer@ while (true) {
        var i = 1L
        while (i * i <= lo) {
            if (lo % i == 0L && i <= n && lo / i <= m) break@outer
            ++i
        }
        ++lo
    }
*/
    bw.write("$lo\n")
    bw.close()
}


import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.util.*
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

val MOD = 1_000_000_007L

inline fun findMin(mn: Long, mx: Long, f: (Long) -> Boolean): Long {
  var low = mn - 1
  var high = mx
  while(high - low > 1) {
    val m = (low + high) / 2
    if (f(m)) high = m
    else low = m
  }
  return high
}
class Solver(stream: InputStream, private val out: java.io.PrintWriter) {
  fun solve() {
    val N = nl()
    val M = nl()
    val K = nl()

    fun test(x: Long): Boolean {
      var sum = 0L
      for (i in 1 .. N) {
        sum += min(M,x / i)
      }

      return sum >= K
    }

    val ans = findMin(0, N * M, ::test)
    out.println(ans)
  }

  private val isDebug = try {
    // なんか本番でエラーでる
    System.getenv("MY_DEBUG") != null
  } catch (t: Throwable) {
    false
  }

  private var tokenizer: StringTokenizer? = null
  private val reader = BufferedReader(InputStreamReader(stream), 32768)
  private fun next(): String {
    while (tokenizer == null || !tokenizer!!.hasMoreTokens()) {
      tokenizer = StringTokenizer(reader.readLine())
    }
    return tokenizer!!.nextToken()
  }

  private fun ni() = next().toInt()
  private fun nl() = next().toLong()
  private fun ns() = next()
  private fun na(n: Int, offset: Int = 0): IntArray {
    return map(n) { ni() + offset }
  }
  private fun nal(n: Int, offset: Int = 0): LongArray {
    val res = LongArray(n)
    for (i in 0 until n) {
      res[i] = nl() + offset
    }
    return res
  }

  private fun na2(n: Int, offset: Int = 0): Array<IntArray> {
    val a  = Array(2){IntArray(n)}
    for (i in 0 until n) {
      for (e in a) {
        e[i] = ni() + offset
      }
    }
    return a
  }

  private inline fun map(n: Int, f: (Int) -> Int): IntArray {
    val res = IntArray(n)
    for (i in 0 until n) {
      res[i] = f(i)
    }
    return res
  }

  private inline fun debug(msg: () -> String) {
    if (isDebug) System.err.println(msg())
  }

  private fun debug(a: LongArray) {
    debug { a.joinToString(" ") }
  }

  private fun debug(a: IntArray) {
    debug { a.joinToString(" ") }
  }

  private fun debug(a: BooleanArray) {
    debug { a.map { if (it) 1 else 0 }.joinToString("") }
  }

  private fun debugDim(A: Array<LongArray>) {
    if (isDebug) {
      for (a in A) {
        debug(a)
      }
    }
  }
  private fun debugDim(A: Array<IntArray>) {
    if (isDebug) {
      for (a in A) {
        debug(a)
      }
    }
  }

  /**
   * 勝手にimport消されるのを防ぎたい
   */
  private fun hoge() {
    min(1, 2)
    max(1, 2)
    abs(-10)
  }
}

fun main() {
  val out = java.io.PrintWriter(System.out)
  Solver(System.`in`, out).solve()
  out.flush()
}


/**
 * Created by seydazimovnurbol on 5/23/17.
 */

import java.util.*
import kotlin.system.exitProcess

fun main(args: Array <String>) {
    var scanner : Scanner = Scanner(System.`in`)
    var n = scanner.nextInt()
    var k = scanner.nextInt()

    var a : ArrayList<Int> = ArrayList<Int>()

    var sum : Double = 0.0
    for (i in 1 .. n) {
        var x = scanner.nextInt()
        a.add(x)
        sum += x
    }
    sum /= n
    var cntK : Int = 0
    for (i in 0 .. n - 1)
        if (a[i] == k) cntK++;

    var need : Int = 0
    for (i in 0 .. n - 1) {
        if (a[i] < k) {
            var cnt : Int = k - 1 - a[i]
            a[i] += Math.min(cnt, cntK)
            cntK -= Math.min(cnt, cntK)
            need += k - 1 - a[i]
        }
    }

    // [A] [B]

    var cntOther : Int = n - cntK
    if (cntK >= cntOther) println(0)
    else if (need == 0) println(cntOther - cntK)
    else println(need + n + need)
}


fun main(args: Array<String>) {
    val x = readLine()!!.split(" ")
    var courses = x[0].toInt()
    val mark = x[1].toInt()

    var sum = readLine()!!.split(" ").map { it.toInt() }.sum().toDouble()

    var ans = 0
    var curMark =  sum / courses
    while ((curMark + .5).toInt() < mark){
        sum += mark
        courses++
        curMark = sum / courses
        ans++
    }
    println(ans)
}


fun main(args: Array<String>) {

    var x= readLine()?.split(" ")
    var n:Int = Integer.parseInt(x!![0])
    var k:Int = Integer.parseInt(x!![1])
    x= readLine()?.split(" ")
    var sum:Double=0.0
    for(i in 1..n){
        sum+=Integer.parseInt(x!![i-1])
    }
    var avg:Double=sum/n
    if(avg+.5>=k){
        println(0)
        return
    }
    var c=0
    while (true){
        sum+=k
        n++
        c++
        avg=sum/n
        if(avg+.5>=k)break
    }
    println(c)

}


fun main(args: Array<String>) {
    var (n, k) = readLine()!!.split(' ').map(String::toInt)
    var total = 0
    readLine()!!.split(' ').map(String::toInt).forEach {
        total += it
    }
    var ans = 0
    while (true) {
        // print("$n $total\n")
        if (total / n >= k)
            break
        else if (total / n >= k - 1 && total % n >= (n+1) / 2)
            break
        ans++
        n++
        total += k
    }
    print("$ans\n")
}


import kotlin.math.max

fun main() {
    fun readInts() = readLine()!!.split(" ").map(String::toInt)

    val m = Array(3) { IntArray(3) }
    for (row in 0 until 3) m[row] = readInts().toIntArray()
    var x = 0 // sum of rows, columns and diagonals
    for (row in 0 until 3) x = max(x, m[row].sum() + 1)
    for (column in 0 until 3) x = max(x, m.fold(0) { acc, arr -> acc + arr[1] } + 1)
    for (row in 0 until 3) m[row][row] = x - m[row].sum()

    // while (m[0][0] + m[1][1] + m[2][2] != x) {
    // x++
    // m[0][0]++
    // m[1][1]++
    // m[2][2]++
    // }
/*
The sum of the diagonal can not sum x yet, but now the relationship is established and the three cells should
be increased by the same value. Which value? Every time we increase them by one x is increased by three, so the
diagonal is two units closer to x (3 - 1). It's possible then to calculate how many times it's necessary to
increment the cells
*/
    val remaining = (x - m[0][0] - m[1][1] - m[2][2]) / 2
    for (row in 0 until 3) m[row][row] += remaining
    print(m.joinToString(System.lineSeparator()) { row -> row.joinToString(" ") })
}


fun main() {
    val line = readLine()!!.split(" ")
    val n = line[0].toInt()
    val mod = line[1].toLong()
    val limit = (n * (n - 1)) / 2
    val dp = Array(n + 1) { LongArray(limit + 1) }
    dp[0][0] = 1L
    var answer = 0L
    for (k in 1..n) {
        for (j in 0..limit) {
            if (j > 0) {
                dp[k][j] += dp[k][j - 1]
            }
            dp[k][j] += dp[k - 1][j]
            if (j >= k) {
                dp[k][j] -= dp[k - 1][j - k]
            }
            if (dp[k][j] >= mod) {
                dp[k][j] -= mod
            }
            if (dp[k][j] < 0L) {
                dp[k][j] += mod
            }
        }
        var here = 0L
        var curr = 0L
        var addend2 = 0L
        var addend1 = 0L
        for (j in 0..limit) {
            here += dp[k - 1][j] * curr
            here %= mod
            curr += addend2
            if (curr >= mod) {
                curr -= mod
            }
            if (j >= k) {
                addend1 -= dp[k - 1][j - k]
            }
            addend1 += dp[k - 1][j]
            if (addend1 >= mod) {
                addend1 -= mod
            }
            if (addend1 < 0L) {
                addend1 += mod
            }
            addend2 += k.toLong() * dp[k - 1][j]
            addend2 -= addend1
            addend2 += mod
            addend2 %= mod
        }
        for (k2 in k + 1..n) {
            here *= k2.toLong()
            here %= mod
        }
        answer += here
        answer %= mod
    }
    println(answer)
}


@file:Suppress("NOTHING_TO_INLINE", "EXPERIMENTAL_FEATURE_WARNING", "OVERRIDE_BY_INLINE")
@file:OptIn(ExperimentalUnsignedTypes::class, ExperimentalStdlibApi::class)

import java.io.PrintWriter
import kotlin.math.*
import kotlin.random.Random
import kotlin.collections.sort as _sort
import kotlin.collections.sortDescending as _sortDescending
import kotlin.io.println as iprintln

/** @author Spheniscine */
fun main() { _writer.solve(); _writer.flush() }
fun PrintWriter.solve() {
//    val startTime = System.nanoTime()

    val numCases = 1//readInt()

    case@ for(case in 1..numCases) {
        //    print("Case #$case: ")

        val n = readInt()
        MOD = readInt()

//        val C = ModIntArray(n+1)
//        C[n]++
//        for(i in 1..n) {
//            for(j in n-i until n) C[j] += C[j+1]
//        }

        var ans = ModInt(0)
        val P = ModIntArray(n+1)
        P[0]++
        for(i in 0 until n) P[i+1] = P[i] * (n - i)

        var D = OffsetModIntArray(0, 0)
        D[0]++
        for(i in 1 until n) {
            for(j in 0 until D.arr.lastIndex) D.arr[j+1] += D.arr[j]
            var acc = ModInt(0)
            for(j in 1..i) acc += D.getPinned(-j-1) * (i - j + 1)

            ans += acc * P[n-i-1]

            acc = ModInt(0)
            val Di = OffsetModIntArray(D.firstIndex - i, D.lastIndex + i)
            for(j in Di.firstIndex .. Di.lastIndex) {
                acc += D.getPinned(j + i) - D.getPinned(j - 1)
                acc -= D.getPinned(j - 1) - D.getPinned(j - i - 2)
                Di[j] = acc
            }
            D = Di
        }

        println(ans.int)
    }

//    iprintln("Time: ${(System.nanoTime() - startTime) / 1000000} ms")
}

fun OffsetModIntArray.getPinned(i: Int) = if (i < firstIndex) ModInt(0) else get(min(i, lastIndex))

class OffsetModIntArray(val firstIndex: Int, val lastIndex: Int) {
    constructor(indices: IntRange): this(indices.first, indices.last)
    inline val indices get() = firstIndex .. lastIndex
    val arr = ModIntArray(lastIndex - firstIndex + 1)
    val size get() = arr.size

    operator fun get(i: Int) = arr[i - firstIndex]
    operator fun set(i: Int, v: ModInt) { arr[i - firstIndex] = v }
    fun last() = arr.last()
}

var MOD = 998244353

infix fun Int.modulo(mod: Int): Int = (this % mod).let { (it shr Int.SIZE_BITS - 1 and mod) + it }
infix fun Long.modulo(mod: Long) = (this % mod).let { (it shr Long.SIZE_BITS - 1 and mod) + it }
infix fun Long.modulo(mod: Int) = modulo(mod.toLong()).toInt()

fun Int.mulMod(other: Int, mod: Int) = toLong() * other modulo mod

fun Int.powMod(exponent: Long, mod: Int): Int {
    if(exponent < 0) error("Inverse not implemented")
    var res = 1L
    var e = exponent
    var b = modulo(mod).toLong()

    while(e > 0) {
        if(e and 1 == 1L) {
            res = res * b % mod
        }
        e = e shr 1
        b = b * b % mod
    }
    return res.toInt()
}
fun Int.powMod(exponent: Int, mod: Int) = powMod(exponent.toLong(), mod)
fun Int.modPowArray(n: Int, mod: Int): IntArray {
    val res = IntArray(n+1)
    res[0] = 1
    for(i in 1..n) res[i] = mulMod(res[i-1], mod)
    return res
}

inline fun Int.toModInt() = ModInt(this modulo MOD)
inline fun Long.toModInt() = ModInt(this modulo MOD)

/** note: Only use constructor for int within modulo range, otherwise use toModInt **/
inline class ModInt(val int: Int) {

    // normalizes an integer that's within range [-MOD, MOD) without branching
    private inline fun normalize(int: Int) = ModInt((int shr Int.SIZE_BITS - 1 and MOD) + int)

    operator fun plus(other: ModInt) = normalize(int + other.int - MOD) // overflow-safe even if MOD >= 2^30
    inline operator fun plus(other: Int) = plus(other.toModInt())
    operator fun inc() = normalize(int + (1 - MOD))

    operator fun minus(other: ModInt) = normalize(int - other.int)
    inline operator fun minus(other: Int) = minus(other.toModInt())
    operator fun dec() = normalize(int - 1)
    operator fun unaryMinus() = normalize(-int)

    operator fun times(other: ModInt) = ModInt((int.toLong() * other.int % MOD).toInt())
    inline operator fun times(other: Int) = ModInt(int.mulMod(other, MOD))

    fun pow(exponent: Int): ModInt = ModInt(int.powMod(exponent, MOD))

    fun pow(exponent: Long) = ModInt(int.powMod(exponent, MOD))

    override inline fun toString() = int.toString()
}

inline operator fun Int.plus(modInt: ModInt) = modInt + this
inline operator fun Int.minus(modInt: ModInt) = toModInt() - modInt
inline operator fun Int.times(modInt: ModInt) = modInt * this

inline class ModIntArray(val intArray: IntArray): Collection<ModInt> {
    inline operator fun get(i: Int) = ModInt(intArray[i])
    inline operator fun set(i: Int, v: ModInt) { intArray[i] = v.int }

    override inline val size: Int get() = intArray.size
    inline val lastIndex get() = intArray.lastIndex
    inline val indices get() = intArray.indices

    override inline fun contains(element: ModInt): Boolean = element.int in intArray

    override fun containsAll(elements: Collection<ModInt>): Boolean = elements.all(::contains)

    override inline fun isEmpty(): Boolean = intArray.isEmpty()

    override fun iterator(): Iterator<ModInt> = object: Iterator<ModInt> {
        var index = 0
        override fun hasNext(): Boolean = index < size
        override fun next(): ModInt = get(index++)
    }

    fun copyOf(newSize: Int) = ModIntArray(intArray.copyOf(newSize))
    fun copyOf() = copyOf(size)
}
fun ModIntArray.copyInto(destination: ModIntArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size) =
    ModIntArray(intArray.copyInto(destination.intArray, destinationOffset, startIndex, endIndex))
inline fun ModIntArray(size: Int) = ModIntArray(IntArray(size))
inline fun ModIntArray(size: Int, init: (Int) -> ModInt) = ModIntArray(IntArray(size) { init(it).int })

fun ModInt.powArray(n: Int) = ModIntArray(int.modPowArray(n, MOD))

inline fun ModIntArray.first() = get(0)
inline fun ModIntArray.last() = get(lastIndex)
inline fun ModIntArray.joinToString(separator: CharSequence) = intArray.joinToString(separator)
inline fun <R> ModIntArray.fold(init: R, op: (acc: R, ModInt) -> R) = intArray.fold(init) { acc, i -> op(acc, ModInt(i)) }
inline fun <R> ModIntArray.foldRight(init: R, op: (ModInt, acc: R) -> R) = intArray.foldRight(init) { i, acc -> op(ModInt(i), acc) }
fun ModIntArray.sum() = fold(ModInt(0), ModInt::plus)
fun ModIntArray.product() = fold(ModInt(1), ModInt::times)

inline fun <T> Iterable<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Iterable<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
inline fun <T> Sequence<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Sequence<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
inline fun <T> Array<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Array<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
fun Iterable<ModInt>.sum() = sumByModInt { it }
fun Sequence<ModInt>.sum() = sumByModInt { it }
fun Iterable<ModInt>.product() = productByModInt { it }
fun Sequence<ModInt>.product() = productByModInt { it }
fun Collection<ModInt>.toModIntArray() = ModIntArray(size).also { var i = 0; for(e in this) { it[i++] = e } }

/** IO */
//@JvmField val ONLINE_JUDGE = System.getProperty("ONLINE_JUDGE") != null
//const val PATH = "src/main/resources/"
//@JvmField val INPUT = File(PATH + "input.txt").inputStream()
//@JvmField val OUTPUT = File(PATH + "output.txt").outputStream()
@JvmField val INPUT = System.`in`
@JvmField val OUTPUT = System.out

const val _BUFFER_SIZE = 1 shl 16
@JvmField val _buffer = ByteArray(_BUFFER_SIZE)
@JvmField var _bufferPt = 0
@JvmField var _bytesRead = 0

tailrec fun readChar(): Char {
    if(_bufferPt == _bytesRead) {
        _bufferPt = 0
        _bytesRead = INPUT.read(_buffer, 0, _BUFFER_SIZE)
    }
    return if(_bytesRead < 0) Char.MIN_VALUE
    else {
        val c = _buffer[_bufferPt++].toChar()
        if (c == '\r') readChar() else c
    }
}

/** @param skipNext Whether to skip the next character (usually whitespace), defaults to true */
fun readCharArray(n: Int, skipNext: Boolean = true): CharArray {
    val res = CharArray(n) { readChar() }
    if(skipNext) readChar()
    return res
}

fun readLine(): String? {
    var c = readChar()
    return if(c == Char.MIN_VALUE) null
    else buildString {
        while(c != '\n' && c != Char.MIN_VALUE) {
            append(c)
            c = readChar()
        }
    }
}
fun readLn() = readLine()!!

fun read() = buildString {
    var c = readChar()
    while(c <= ' ') {
        if(c == Char.MIN_VALUE) return@buildString
        c = readChar()
    }
    do {
        append(c)
        c = readChar()
    } while(c > ' ')
}
fun readInt() = read().toInt()
fun readDouble() = read().toDouble()
fun readLong() = read().toLong()
fun readStrings(n: Int) = List(n) { read() }
fun readLines(n: Int) = List(n) { readLn() }
fun readInts(n: Int) = List(n) { read().toInt() }
fun readIntArray(n: Int) = IntArray(n) { read().toInt() }
fun readDoubles(n: Int) = List(n) { read().toDouble() }
fun readDoubleArray(n: Int) = DoubleArray(n) { read().toDouble() }
fun readLongs(n: Int) = List(n) { read().toLong() }
fun readLongArray(n: Int) = LongArray(n) { read().toLong() }

@JvmField val _writer = PrintWriter(OUTPUT, false)

/**  sort overrides to avoid quicksort attacks */

@JvmField var _random: Random? = null
val random get() = _random ?: Random(0x594E215C123 * System.nanoTime()).also { _random = it }

inline fun <A, T> _mergeSort(a0: A, n: Int, tmp0: A, get: A.(Int) -> T, set: A.(Int, T) -> Unit, cmp: (T, T) -> Int) {
    var a = a0
    var tmp = tmp0
    var len = 1
    while(len < n) {
        var l = 0
        while(true) {
            val m = l + len
            if(m >= n) break
            val r = min(n, m + len)
            var i = l
            var j = m
            for(k in l until r) {
                if(i != m && (j == r || cmp(a.get(i), a.get(j)) <= 0)) {
                    tmp.set(k, a.get(i++))
                } else tmp.set(k, a.get(j++))
            }
            l = r
        }
        for(i in l until n) tmp.set(i, a.get(i))
        val t = a; a = tmp; tmp = t
        len += len
    }
    if(a !== a0) for(i in 0 until n) a0.set(i, tmp0.get(i))
}

inline fun IntArray.sortWith(cmp: (Int, Int) -> Int) { _mergeSort(this, size, IntArray(size), IntArray::get, IntArray::set, cmp) }
inline fun <T: Comparable<T>> IntArray.sortBy(func: (Int) -> T) { sortWith { a, b -> func(a).compareTo(func(b)) } }
inline fun <T: Comparable<T>> IntArray.sortByDescending(func: (Int) -> T) { sortWith { a, b -> func(b).compareTo(func(a)) } }
fun IntArray.sort() { sortBy { it } }
fun IntArray.sortDescending() { sortByDescending { it } }

inline fun LongArray.sortWith(cmp: (Long, Long) -> Int) { _mergeSort(this, size, LongArray(size), LongArray::get, LongArray::set, cmp) }
inline fun <T: Comparable<T>> LongArray.sortBy(func: (Long) -> T) { sortWith { a, b -> func(a).compareTo(func(b)) } }
inline fun <T: Comparable<T>> LongArray.sortByDescending(func: (Long) -> T) { sortWith { a, b -> func(b).compareTo(func(a)) } }
fun LongArray.sort() { sortBy { it } }
fun LongArray.sortDescending() { sortByDescending { it } }

inline fun DoubleArray.sortWith(cmp: (Double, Double) -> Int) { _mergeSort(this, size, DoubleArray(size), DoubleArray::get, DoubleArray::set, cmp) }
inline fun <T: Comparable<T>> DoubleArray.sortBy(func: (Double) -> T) { sortWith { a, b -> func(a).compareTo(func(b)) } }
inline fun <T: Comparable<T>> DoubleArray.sortByDescending(func: (Double) -> T) { sortWith { a, b -> func(b).compareTo(func(a)) } }
fun DoubleArray.sort() { sortBy { it } }
fun DoubleArray.sortDescending() { sortByDescending { it } }

inline fun CharArray.sort() { _sort() }
inline fun CharArray.sortDescending() { _sortDescending() }

inline fun <T : Comparable<T>> Array<out T>.sort() = _sort()
inline fun <T : Comparable<T>> Array<out T>.sortDescending() = _sortDescending()
inline fun <T : Comparable<T>> MutableList<out T>.sort() = _sort()
inline fun <T : Comparable<T>> MutableList<out T>.sortDescending() = _sortDescending()

// import preserving junk function
@Suppress("NonAsciiCharacters") fun 雪花飄飄北風嘯嘯天地一片蒼茫() { iprintln(max(1, 2)) }

fun IntArray.sumLong() = sumOf { it.toLong() }

fun IntArray.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun IntArray.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun LongArray.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun LongArray.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun DoubleArray.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun DoubleArray.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun <T: Comparable<T>> Array<T>.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun <T: Comparable<T>> Array<T>.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun <T: Comparable<T>> List<T>.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun <T: Comparable<T>> List<T>.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }

// max/min Kotlin 1.6 -> 1.4 shim
fun IntArray.max() = maxOf { it }
fun IntArray.min() = minOf { it }
fun LongArray.max() = maxOf { it }
fun LongArray.min() = minOf { it }
fun CharArray.max() = maxOf { it }
fun CharArray.min() = minOf { it }
fun <T : Comparable<T>> Iterable<T>.max() = maxOf { it }
fun <T : Comparable<T>> Iterable<T>.min() = minOf { it }
fun <T : Comparable<T>> Sequence<T>.max() = maxOf { it }
fun <T : Comparable<T>> Sequence<T>.min() = minOf { it }


@file:Suppress("NOTHING_TO_INLINE", "EXPERIMENTAL_FEATURE_WARNING", "OVERRIDE_BY_INLINE")
@file:OptIn(ExperimentalUnsignedTypes::class, ExperimentalStdlibApi::class)

import java.io.PrintWriter
import kotlin.math.*
import kotlin.random.Random
import kotlin.collections.sort as _sort
import kotlin.collections.sortDescending as _sortDescending
import kotlin.io.println as iprintln

/** @author Spheniscine */
fun main() { _writer.solve(); _writer.flush() }
fun PrintWriter.solve() {
//    val startTime = System.nanoTime()

    val numCases = 1//readInt()

    case@ for(case in 1..numCases) {
        //    print("Case #$case: ")

        val n = readInt()
        MOD = readInt()

//        val C = ModIntArray(n+1)
//        C[n]++
//        for(i in 1..n) {
//            for(j in n-i until n) C[j] += C[j+1]
//        }

        var ans = ModInt(0)
        val P = ModIntArray(n+1)
        P[0]++
        for(i in 0 until n) P[i+1] = P[i] * (n - i)

        var D = OffsetModIntArray(0, 0)
        D[0]++
        for(i in 2..n) {
            for(j in 0 until D.arr.lastIndex) D.arr[j+1] += D.arr[j]
            var acc = ModInt(0)
            for(j in 1 until i) acc += D.getPinned(-j-1) * (i - j)

            ans += acc * P[n-i]

            acc = ModInt(0)
            val Di = OffsetModIntArray(D.firstIndex - i + 1, D.lastIndex + i - 1)
            for(j in Di.firstIndex .. Di.lastIndex) {
                acc += D.getPinned(j + i - 1) - D.getPinned(j - 1)
                acc -= D.getPinned(j - 1) - D.getPinned(j - i - 1)
                Di[j] = acc
            }
            D = Di
        }

        println(ans.int)
    }

//    iprintln("Time: ${(System.nanoTime() - startTime) / 1000000} ms")
}

fun OffsetModIntArray.getPinned(i: Int) = if (i < firstIndex) ModInt(0) else get(min(i, lastIndex))

class OffsetModIntArray(val firstIndex: Int, val lastIndex: Int) {
    constructor(indices: IntRange): this(indices.first, indices.last)
    inline val indices get() = firstIndex .. lastIndex
    val arr = ModIntArray(lastIndex - firstIndex + 1)
    val size get() = arr.size

    operator fun get(i: Int) = arr[i - firstIndex]
    operator fun set(i: Int, v: ModInt) { arr[i - firstIndex] = v }
    fun last() = arr.last()
}

var MOD = 998244353

infix fun Int.modulo(mod: Int): Int = (this % mod).let { (it shr Int.SIZE_BITS - 1 and mod) + it }
infix fun Long.modulo(mod: Long) = (this % mod).let { (it shr Long.SIZE_BITS - 1 and mod) + it }
infix fun Long.modulo(mod: Int) = modulo(mod.toLong()).toInt()

fun Int.mulMod(other: Int, mod: Int) = toLong() * other modulo mod

fun Int.powMod(exponent: Long, mod: Int): Int {
    if(exponent < 0) error("Inverse not implemented")
    var res = 1L
    var e = exponent
    var b = modulo(mod).toLong()

    while(e > 0) {
        if(e and 1 == 1L) {
            res = res * b % mod
        }
        e = e shr 1
        b = b * b % mod
    }
    return res.toInt()
}
fun Int.powMod(exponent: Int, mod: Int) = powMod(exponent.toLong(), mod)
fun Int.modPowArray(n: Int, mod: Int): IntArray {
    val res = IntArray(n+1)
    res[0] = 1
    for(i in 1..n) res[i] = mulMod(res[i-1], mod)
    return res
}

inline fun Int.toModInt() = ModInt(this modulo MOD)
inline fun Long.toModInt() = ModInt(this modulo MOD)

/** note: Only use constructor for int within modulo range, otherwise use toModInt **/
inline class ModInt(val int: Int) {

    // normalizes an integer that's within range [-MOD, MOD) without branching
    private inline fun normalize(int: Int) = ModInt((int shr Int.SIZE_BITS - 1 and MOD) + int)

    operator fun plus(other: ModInt) = normalize(int + other.int - MOD) // overflow-safe even if MOD >= 2^30
    inline operator fun plus(other: Int) = plus(other.toModInt())
    operator fun inc() = normalize(int + (1 - MOD))

    operator fun minus(other: ModInt) = normalize(int - other.int)
    inline operator fun minus(other: Int) = minus(other.toModInt())
    operator fun dec() = normalize(int - 1)
    operator fun unaryMinus() = normalize(-int)

    operator fun times(other: ModInt) = ModInt((int.toLong() * other.int % MOD).toInt())
    inline operator fun times(other: Int) = ModInt(int.mulMod(other, MOD))

    fun pow(exponent: Int): ModInt = ModInt(int.powMod(exponent, MOD))

    fun pow(exponent: Long) = ModInt(int.powMod(exponent, MOD))

    override inline fun toString() = int.toString()
}

inline operator fun Int.plus(modInt: ModInt) = modInt + this
inline operator fun Int.minus(modInt: ModInt) = toModInt() - modInt
inline operator fun Int.times(modInt: ModInt) = modInt * this

inline class ModIntArray(val intArray: IntArray): Collection<ModInt> {
    inline operator fun get(i: Int) = ModInt(intArray[i])
    inline operator fun set(i: Int, v: ModInt) { intArray[i] = v.int }

    override inline val size: Int get() = intArray.size
    inline val lastIndex get() = intArray.lastIndex
    inline val indices get() = intArray.indices

    override inline fun contains(element: ModInt): Boolean = element.int in intArray

    override fun containsAll(elements: Collection<ModInt>): Boolean = elements.all(::contains)

    override inline fun isEmpty(): Boolean = intArray.isEmpty()

    override fun iterator(): Iterator<ModInt> = object: Iterator<ModInt> {
        var index = 0
        override fun hasNext(): Boolean = index < size
        override fun next(): ModInt = get(index++)
    }

    fun copyOf(newSize: Int) = ModIntArray(intArray.copyOf(newSize))
    fun copyOf() = copyOf(size)
}
fun ModIntArray.copyInto(destination: ModIntArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size) =
    ModIntArray(intArray.copyInto(destination.intArray, destinationOffset, startIndex, endIndex))
inline fun ModIntArray(size: Int) = ModIntArray(IntArray(size))
inline fun ModIntArray(size: Int, init: (Int) -> ModInt) = ModIntArray(IntArray(size) { init(it).int })

fun ModInt.powArray(n: Int) = ModIntArray(int.modPowArray(n, MOD))

inline fun ModIntArray.first() = get(0)
inline fun ModIntArray.last() = get(lastIndex)
inline fun ModIntArray.joinToString(separator: CharSequence) = intArray.joinToString(separator)
inline fun <R> ModIntArray.fold(init: R, op: (acc: R, ModInt) -> R) = intArray.fold(init) { acc, i -> op(acc, ModInt(i)) }
inline fun <R> ModIntArray.foldRight(init: R, op: (ModInt, acc: R) -> R) = intArray.foldRight(init) { i, acc -> op(ModInt(i), acc) }
fun ModIntArray.sum() = fold(ModInt(0), ModInt::plus)
fun ModIntArray.product() = fold(ModInt(1), ModInt::times)

inline fun <T> Iterable<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Iterable<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
inline fun <T> Sequence<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Sequence<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
inline fun <T> Array<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Array<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
fun Iterable<ModInt>.sum() = sumByModInt { it }
fun Sequence<ModInt>.sum() = sumByModInt { it }
fun Iterable<ModInt>.product() = productByModInt { it }
fun Sequence<ModInt>.product() = productByModInt { it }
fun Collection<ModInt>.toModIntArray() = ModIntArray(size).also { var i = 0; for(e in this) { it[i++] = e } }

/** IO */
//@JvmField val ONLINE_JUDGE = System.getProperty("ONLINE_JUDGE") != null
//const val PATH = "src/main/resources/"
//@JvmField val INPUT = File(PATH + "input.txt").inputStream()
//@JvmField val OUTPUT = File(PATH + "output.txt").outputStream()
@JvmField val INPUT = System.`in`
@JvmField val OUTPUT = System.out

const val _BUFFER_SIZE = 1 shl 16
@JvmField val _buffer = ByteArray(_BUFFER_SIZE)
@JvmField var _bufferPt = 0
@JvmField var _bytesRead = 0

tailrec fun readChar(): Char {
    if(_bufferPt == _bytesRead) {
        _bufferPt = 0
        _bytesRead = INPUT.read(_buffer, 0, _BUFFER_SIZE)
    }
    return if(_bytesRead < 0) Char.MIN_VALUE
    else {
        val c = _buffer[_bufferPt++].toChar()
        if (c == '\r') readChar() else c
    }
}

/** @param skipNext Whether to skip the next character (usually whitespace), defaults to true */
fun readCharArray(n: Int, skipNext: Boolean = true): CharArray {
    val res = CharArray(n) { readChar() }
    if(skipNext) readChar()
    return res
}

fun readLine(): String? {
    var c = readChar()
    return if(c == Char.MIN_VALUE) null
    else buildString {
        while(c != '\n' && c != Char.MIN_VALUE) {
            append(c)
            c = readChar()
        }
    }
}
fun readLn() = readLine()!!

fun read() = buildString {
    var c = readChar()
    while(c <= ' ') {
        if(c == Char.MIN_VALUE) return@buildString
        c = readChar()
    }
    do {
        append(c)
        c = readChar()
    } while(c > ' ')
}
fun readInt() = read().toInt()
fun readDouble() = read().toDouble()
fun readLong() = read().toLong()
fun readStrings(n: Int) = List(n) { read() }
fun readLines(n: Int) = List(n) { readLn() }
fun readInts(n: Int) = List(n) { read().toInt() }
fun readIntArray(n: Int) = IntArray(n) { read().toInt() }
fun readDoubles(n: Int) = List(n) { read().toDouble() }
fun readDoubleArray(n: Int) = DoubleArray(n) { read().toDouble() }
fun readLongs(n: Int) = List(n) { read().toLong() }
fun readLongArray(n: Int) = LongArray(n) { read().toLong() }

@JvmField val _writer = PrintWriter(OUTPUT, false)

/**  sort overrides to avoid quicksort attacks */

@JvmField var _random: Random? = null
val random get() = _random ?: Random(0x594E215C123 * System.nanoTime()).also { _random = it }

inline fun <A, T> _mergeSort(a0: A, n: Int, tmp0: A, get: A.(Int) -> T, set: A.(Int, T) -> Unit, cmp: (T, T) -> Int) {
    var a = a0
    var tmp = tmp0
    var len = 1
    while(len < n) {
        var l = 0
        while(true) {
            val m = l + len
            if(m >= n) break
            val r = min(n, m + len)
            var i = l
            var j = m
            for(k in l until r) {
                if(i != m && (j == r || cmp(a.get(i), a.get(j)) <= 0)) {
                    tmp.set(k, a.get(i++))
                } else tmp.set(k, a.get(j++))
            }
            l = r
        }
        for(i in l until n) tmp.set(i, a.get(i))
        val t = a; a = tmp; tmp = t
        len += len
    }
    if(a !== a0) for(i in 0 until n) a0.set(i, tmp0.get(i))
}

inline fun IntArray.sortWith(cmp: (Int, Int) -> Int) { _mergeSort(this, size, IntArray(size), IntArray::get, IntArray::set, cmp) }
inline fun <T: Comparable<T>> IntArray.sortBy(func: (Int) -> T) { sortWith { a, b -> func(a).compareTo(func(b)) } }
inline fun <T: Comparable<T>> IntArray.sortByDescending(func: (Int) -> T) { sortWith { a, b -> func(b).compareTo(func(a)) } }
fun IntArray.sort() { sortBy { it } }
fun IntArray.sortDescending() { sortByDescending { it } }

inline fun LongArray.sortWith(cmp: (Long, Long) -> Int) { _mergeSort(this, size, LongArray(size), LongArray::get, LongArray::set, cmp) }
inline fun <T: Comparable<T>> LongArray.sortBy(func: (Long) -> T) { sortWith { a, b -> func(a).compareTo(func(b)) } }
inline fun <T: Comparable<T>> LongArray.sortByDescending(func: (Long) -> T) { sortWith { a, b -> func(b).compareTo(func(a)) } }
fun LongArray.sort() { sortBy { it } }
fun LongArray.sortDescending() { sortByDescending { it } }

inline fun DoubleArray.sortWith(cmp: (Double, Double) -> Int) { _mergeSort(this, size, DoubleArray(size), DoubleArray::get, DoubleArray::set, cmp) }
inline fun <T: Comparable<T>> DoubleArray.sortBy(func: (Double) -> T) { sortWith { a, b -> func(a).compareTo(func(b)) } }
inline fun <T: Comparable<T>> DoubleArray.sortByDescending(func: (Double) -> T) { sortWith { a, b -> func(b).compareTo(func(a)) } }
fun DoubleArray.sort() { sortBy { it } }
fun DoubleArray.sortDescending() { sortByDescending { it } }

inline fun CharArray.sort() { _sort() }
inline fun CharArray.sortDescending() { _sortDescending() }

inline fun <T : Comparable<T>> Array<out T>.sort() = _sort()
inline fun <T : Comparable<T>> Array<out T>.sortDescending() = _sortDescending()
inline fun <T : Comparable<T>> MutableList<out T>.sort() = _sort()
inline fun <T : Comparable<T>> MutableList<out T>.sortDescending() = _sortDescending()

// import preserving junk function
@Suppress("NonAsciiCharacters") fun 雪花飄飄北風嘯嘯天地一片蒼茫() { iprintln(max(1, 2)) }

fun IntArray.sumLong() = sumOf { it.toLong() }

fun IntArray.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun IntArray.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun LongArray.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun LongArray.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun DoubleArray.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun DoubleArray.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun <T: Comparable<T>> Array<T>.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun <T: Comparable<T>> Array<T>.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun <T: Comparable<T>> List<T>.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun <T: Comparable<T>> List<T>.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }

// max/min Kotlin 1.6 -> 1.4 shim
fun IntArray.max() = maxOf { it }
fun IntArray.min() = minOf { it }
fun LongArray.max() = maxOf { it }
fun LongArray.min() = minOf { it }
fun CharArray.max() = maxOf { it }
fun CharArray.min() = minOf { it }
fun <T : Comparable<T>> Iterable<T>.max() = maxOf { it }
fun <T : Comparable<T>> Iterable<T>.min() = minOf { it }
fun <T : Comparable<T>> Sequence<T>.max() = maxOf { it }
fun <T : Comparable<T>> Sequence<T>.min() = minOf { it }


@file:Suppress("NOTHING_TO_INLINE", "EXPERIMENTAL_FEATURE_WARNING", "OVERRIDE_BY_INLINE")
@file:OptIn(ExperimentalUnsignedTypes::class, ExperimentalStdlibApi::class)

import java.io.PrintWriter
import kotlin.math.*
import kotlin.random.Random
import kotlin.collections.sort as _sort
import kotlin.collections.sortDescending as _sortDescending
import kotlin.io.println as iprintln

/** @author Spheniscine */
fun main() { _writer.solve(); _writer.flush() }
fun PrintWriter.solve() {
//    val startTime = System.nanoTime()

    val numCases = 1//readInt()

    case@ for(case in 1..numCases) {
        //    print("Case #$case: ")

        val n = readInt()
        MOD = readInt()

//        val C = ModIntArray(n+1)
//        C[n]++
//        for(i in 1..n) {
//            for(j in n-i until n) C[j] += C[j+1]
//        }

        var ans = ModInt(0)
        val P = ModIntArray(n+1)
        P[0]++
        for(i in 0 until n) P[i+1] = P[i] * (n - i)

        var D = OffsetModIntArray(0, 0)
        D[0]++
        for(i in 2..n) {
            for(j in 0 until D.arr.lastIndex) D.arr[j+1] += D.arr[j]
            var acc = ModInt(0)
            for(j in 1 until i) acc += D.getPinned(-j-1) * (i - j)

            ans += acc * P[n-i]

            acc = ModInt(0)
            val Di = OffsetModIntArray(D.firstIndex - i, D.lastIndex + i)
            for(j in Di.firstIndex .. Di.lastIndex) {
                acc += D.getPinned(j + i - 1) - D.getPinned(j - 1)
                acc -= D.getPinned(j - 1) - D.getPinned(j - i - 1)
                Di[j] = acc
            }
            D = Di
        }

        println(ans.int)
    }

//    iprintln("Time: ${(System.nanoTime() - startTime) / 1000000} ms")
}

fun OffsetModIntArray.getPinned(i: Int) = if (i < firstIndex) ModInt(0) else get(min(i, lastIndex))

class OffsetModIntArray(val firstIndex: Int, val lastIndex: Int) {
    constructor(indices: IntRange): this(indices.first, indices.last)
    inline val indices get() = firstIndex .. lastIndex
    val arr = ModIntArray(lastIndex - firstIndex + 1)
    val size get() = arr.size

    operator fun get(i: Int) = arr[i - firstIndex]
    operator fun set(i: Int, v: ModInt) { arr[i - firstIndex] = v }
    fun last() = arr.last()
}

var MOD = 998244353

infix fun Int.modulo(mod: Int): Int = (this % mod).let { (it shr Int.SIZE_BITS - 1 and mod) + it }
infix fun Long.modulo(mod: Long) = (this % mod).let { (it shr Long.SIZE_BITS - 1 and mod) + it }
infix fun Long.modulo(mod: Int) = modulo(mod.toLong()).toInt()

fun Int.mulMod(other: Int, mod: Int) = toLong() * other modulo mod

fun Int.powMod(exponent: Long, mod: Int): Int {
    if(exponent < 0) error("Inverse not implemented")
    var res = 1L
    var e = exponent
    var b = modulo(mod).toLong()

    while(e > 0) {
        if(e and 1 == 1L) {
            res = res * b % mod
        }
        e = e shr 1
        b = b * b % mod
    }
    return res.toInt()
}
fun Int.powMod(exponent: Int, mod: Int) = powMod(exponent.toLong(), mod)
fun Int.modPowArray(n: Int, mod: Int): IntArray {
    val res = IntArray(n+1)
    res[0] = 1
    for(i in 1..n) res[i] = mulMod(res[i-1], mod)
    return res
}

inline fun Int.toModInt() = ModInt(this modulo MOD)
inline fun Long.toModInt() = ModInt(this modulo MOD)

/** note: Only use constructor for int within modulo range, otherwise use toModInt **/
inline class ModInt(val int: Int) {

    // normalizes an integer that's within range [-MOD, MOD) without branching
    private inline fun normalize(int: Int) = ModInt((int shr Int.SIZE_BITS - 1 and MOD) + int)

    operator fun plus(other: ModInt) = normalize(int + other.int - MOD) // overflow-safe even if MOD >= 2^30
    inline operator fun plus(other: Int) = plus(other.toModInt())
    operator fun inc() = normalize(int + (1 - MOD))

    operator fun minus(other: ModInt) = normalize(int - other.int)
    inline operator fun minus(other: Int) = minus(other.toModInt())
    operator fun dec() = normalize(int - 1)
    operator fun unaryMinus() = normalize(-int)

    operator fun times(other: ModInt) = ModInt((int.toLong() * other.int % MOD).toInt())
    inline operator fun times(other: Int) = ModInt(int.mulMod(other, MOD))

    fun pow(exponent: Int): ModInt = ModInt(int.powMod(exponent, MOD))

    fun pow(exponent: Long) = ModInt(int.powMod(exponent, MOD))

    override inline fun toString() = int.toString()
}

inline operator fun Int.plus(modInt: ModInt) = modInt + this
inline operator fun Int.minus(modInt: ModInt) = toModInt() - modInt
inline operator fun Int.times(modInt: ModInt) = modInt * this

inline class ModIntArray(val intArray: IntArray): Collection<ModInt> {
    inline operator fun get(i: Int) = ModInt(intArray[i])
    inline operator fun set(i: Int, v: ModInt) { intArray[i] = v.int }

    override inline val size: Int get() = intArray.size
    inline val lastIndex get() = intArray.lastIndex
    inline val indices get() = intArray.indices

    override inline fun contains(element: ModInt): Boolean = element.int in intArray

    override fun containsAll(elements: Collection<ModInt>): Boolean = elements.all(::contains)

    override inline fun isEmpty(): Boolean = intArray.isEmpty()

    override fun iterator(): Iterator<ModInt> = object: Iterator<ModInt> {
        var index = 0
        override fun hasNext(): Boolean = index < size
        override fun next(): ModInt = get(index++)
    }

    fun copyOf(newSize: Int) = ModIntArray(intArray.copyOf(newSize))
    fun copyOf() = copyOf(size)
}
fun ModIntArray.copyInto(destination: ModIntArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size) =
    ModIntArray(intArray.copyInto(destination.intArray, destinationOffset, startIndex, endIndex))
inline fun ModIntArray(size: Int) = ModIntArray(IntArray(size))
inline fun ModIntArray(size: Int, init: (Int) -> ModInt) = ModIntArray(IntArray(size) { init(it).int })

fun ModInt.powArray(n: Int) = ModIntArray(int.modPowArray(n, MOD))

inline fun ModIntArray.first() = get(0)
inline fun ModIntArray.last() = get(lastIndex)
inline fun ModIntArray.joinToString(separator: CharSequence) = intArray.joinToString(separator)
inline fun <R> ModIntArray.fold(init: R, op: (acc: R, ModInt) -> R) = intArray.fold(init) { acc, i -> op(acc, ModInt(i)) }
inline fun <R> ModIntArray.foldRight(init: R, op: (ModInt, acc: R) -> R) = intArray.foldRight(init) { i, acc -> op(ModInt(i), acc) }
fun ModIntArray.sum() = fold(ModInt(0), ModInt::plus)
fun ModIntArray.product() = fold(ModInt(1), ModInt::times)

inline fun <T> Iterable<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Iterable<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
inline fun <T> Sequence<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Sequence<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
inline fun <T> Array<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Array<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
fun Iterable<ModInt>.sum() = sumByModInt { it }
fun Sequence<ModInt>.sum() = sumByModInt { it }
fun Iterable<ModInt>.product() = productByModInt { it }
fun Sequence<ModInt>.product() = productByModInt { it }
fun Collection<ModInt>.toModIntArray() = ModIntArray(size).also { var i = 0; for(e in this) { it[i++] = e } }

/** IO */
//@JvmField val ONLINE_JUDGE = System.getProperty("ONLINE_JUDGE") != null
//const val PATH = "src/main/resources/"
//@JvmField val INPUT = File(PATH + "input.txt").inputStream()
//@JvmField val OUTPUT = File(PATH + "output.txt").outputStream()
@JvmField val INPUT = System.`in`
@JvmField val OUTPUT = System.out

const val _BUFFER_SIZE = 1 shl 16
@JvmField val _buffer = ByteArray(_BUFFER_SIZE)
@JvmField var _bufferPt = 0
@JvmField var _bytesRead = 0

tailrec fun readChar(): Char {
    if(_bufferPt == _bytesRead) {
        _bufferPt = 0
        _bytesRead = INPUT.read(_buffer, 0, _BUFFER_SIZE)
    }
    return if(_bytesRead < 0) Char.MIN_VALUE
    else {
        val c = _buffer[_bufferPt++].toChar()
        if (c == '\r') readChar() else c
    }
}

/** @param skipNext Whether to skip the next character (usually whitespace), defaults to true */
fun readCharArray(n: Int, skipNext: Boolean = true): CharArray {
    val res = CharArray(n) { readChar() }
    if(skipNext) readChar()
    return res
}

fun readLine(): String? {
    var c = readChar()
    return if(c == Char.MIN_VALUE) null
    else buildString {
        while(c != '\n' && c != Char.MIN_VALUE) {
            append(c)
            c = readChar()
        }
    }
}
fun readLn() = readLine()!!

fun read() = buildString {
    var c = readChar()
    while(c <= ' ') {
        if(c == Char.MIN_VALUE) return@buildString
        c = readChar()
    }
    do {
        append(c)
        c = readChar()
    } while(c > ' ')
}
fun readInt() = read().toInt()
fun readDouble() = read().toDouble()
fun readLong() = read().toLong()
fun readStrings(n: Int) = List(n) { read() }
fun readLines(n: Int) = List(n) { readLn() }
fun readInts(n: Int) = List(n) { read().toInt() }
fun readIntArray(n: Int) = IntArray(n) { read().toInt() }
fun readDoubles(n: Int) = List(n) { read().toDouble() }
fun readDoubleArray(n: Int) = DoubleArray(n) { read().toDouble() }
fun readLongs(n: Int) = List(n) { read().toLong() }
fun readLongArray(n: Int) = LongArray(n) { read().toLong() }

@JvmField val _writer = PrintWriter(OUTPUT, false)

/**  sort overrides to avoid quicksort attacks */

@JvmField var _random: Random? = null
val random get() = _random ?: Random(0x594E215C123 * System.nanoTime()).also { _random = it }

inline fun <A, T> _mergeSort(a0: A, n: Int, tmp0: A, get: A.(Int) -> T, set: A.(Int, T) -> Unit, cmp: (T, T) -> Int) {
    var a = a0
    var tmp = tmp0
    var len = 1
    while(len < n) {
        var l = 0
        while(true) {
            val m = l + len
            if(m >= n) break
            val r = min(n, m + len)
            var i = l
            var j = m
            for(k in l until r) {
                if(i != m && (j == r || cmp(a.get(i), a.get(j)) <= 0)) {
                    tmp.set(k, a.get(i++))
                } else tmp.set(k, a.get(j++))
            }
            l = r
        }
        for(i in l until n) tmp.set(i, a.get(i))
        val t = a; a = tmp; tmp = t
        len += len
    }
    if(a !== a0) for(i in 0 until n) a0.set(i, tmp0.get(i))
}

inline fun IntArray.sortWith(cmp: (Int, Int) -> Int) { _mergeSort(this, size, IntArray(size), IntArray::get, IntArray::set, cmp) }
inline fun <T: Comparable<T>> IntArray.sortBy(func: (Int) -> T) { sortWith { a, b -> func(a).compareTo(func(b)) } }
inline fun <T: Comparable<T>> IntArray.sortByDescending(func: (Int) -> T) { sortWith { a, b -> func(b).compareTo(func(a)) } }
fun IntArray.sort() { sortBy { it } }
fun IntArray.sortDescending() { sortByDescending { it } }

inline fun LongArray.sortWith(cmp: (Long, Long) -> Int) { _mergeSort(this, size, LongArray(size), LongArray::get, LongArray::set, cmp) }
inline fun <T: Comparable<T>> LongArray.sortBy(func: (Long) -> T) { sortWith { a, b -> func(a).compareTo(func(b)) } }
inline fun <T: Comparable<T>> LongArray.sortByDescending(func: (Long) -> T) { sortWith { a, b -> func(b).compareTo(func(a)) } }
fun LongArray.sort() { sortBy { it } }
fun LongArray.sortDescending() { sortByDescending { it } }

inline fun DoubleArray.sortWith(cmp: (Double, Double) -> Int) { _mergeSort(this, size, DoubleArray(size), DoubleArray::get, DoubleArray::set, cmp) }
inline fun <T: Comparable<T>> DoubleArray.sortBy(func: (Double) -> T) { sortWith { a, b -> func(a).compareTo(func(b)) } }
inline fun <T: Comparable<T>> DoubleArray.sortByDescending(func: (Double) -> T) { sortWith { a, b -> func(b).compareTo(func(a)) } }
fun DoubleArray.sort() { sortBy { it } }
fun DoubleArray.sortDescending() { sortByDescending { it } }

inline fun CharArray.sort() { _sort() }
inline fun CharArray.sortDescending() { _sortDescending() }

inline fun <T : Comparable<T>> Array<out T>.sort() = _sort()
inline fun <T : Comparable<T>> Array<out T>.sortDescending() = _sortDescending()
inline fun <T : Comparable<T>> MutableList<out T>.sort() = _sort()
inline fun <T : Comparable<T>> MutableList<out T>.sortDescending() = _sortDescending()

// import preserving junk function
@Suppress("NonAsciiCharacters") fun 雪花飄飄北風嘯嘯天地一片蒼茫() { iprintln(max(1, 2)) }

fun IntArray.sumLong() = sumOf { it.toLong() }

fun IntArray.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun IntArray.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun LongArray.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun LongArray.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun DoubleArray.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun DoubleArray.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun <T: Comparable<T>> Array<T>.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun <T: Comparable<T>> Array<T>.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }
fun <T: Comparable<T>> List<T>.sortedIndices() = IntArray(size) { it }.also { it.sortBy(::get) }
fun <T: Comparable<T>> List<T>.sortedIndicesDescending() = IntArray(size) { it }.also { it.sortByDescending(::get) }

// max/min Kotlin 1.6 -> 1.4 shim
fun IntArray.max() = maxOf { it }
fun IntArray.min() = minOf { it }
fun LongArray.max() = maxOf { it }
fun LongArray.min() = minOf { it }
fun CharArray.max() = maxOf { it }
fun CharArray.min() = minOf { it }
fun <T : Comparable<T>> Iterable<T>.max() = maxOf { it }
fun <T : Comparable<T>> Iterable<T>.min() = minOf { it }
fun <T : Comparable<T>> Sequence<T>.max() = maxOf { it }
fun <T : Comparable<T>> Sequence<T>.min() = minOf { it }


import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.util.*
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

val MOD = 1_000_000_007

class Solver(stream: InputStream, private val out: java.io.PrintWriter) {
  fun solve() {
    val cnt1 = nl()
    val cnt2 = nl()
    val X = nl()
    val Y = nl()

    val MAX = if (isDebug) 10 else Long.MAX_VALUE / 2 // 2e18ぐらいでok
    val ans = findMin(1L, MAX) { a ->
      val x = a / X
      val y = a / Y
      val xy = a / (X * Y)
      val notX = a - x
      val notY = a - y
      val notXy = a - (x + y - xy)
      val need1 = max(0, cnt1 - notX + notXy)
      val need2 = max(0, cnt2 - notY + notXy)
      debug{"$a $notX $notY $notXy $need1 $need2"}
      notXy >= need1 + need2
    }
    out.print(ans)
  }

  /**
   * [l, r]
   */
  fun findMin(l: Long, r: Long, f: (Long) -> Boolean): Long {
    // (l, h]
    var low = l - 1
    var high = r
    while(high - low > 1) {
      val m = (low + high) / 2
      if (f(m)) high = m
      else low = m
    }
    return high
  }

  private val isDebug = try {
    // なんか本番でエラーでる
    System.getenv("MY_DEBUG") != null
  } catch (t: Throwable) {
    false
  }

  private var tokenizer: StringTokenizer? = null
  private val reader = BufferedReader(InputStreamReader(stream), 32768)
  private fun next(): String {
    while (tokenizer == null || !tokenizer!!.hasMoreTokens()) {
      tokenizer = StringTokenizer(reader.readLine())
    }
    return tokenizer!!.nextToken()
  }

  private fun ni() = next().toInt()
  private fun nl() = next().toLong()
  private fun ns() = next()
  private fun na(n: Int, offset: Int = 0): IntArray {
    return map(n, offset) { ni() }
  }

  private inline fun map(n: Int, offset: Int = 0, f: (Int) -> Int): IntArray {
    val res = IntArray(n)
    for (i in 0 until n) {
      res[i] = f(i + offset)
    }
    return res
  }

  private inline fun debug(msg: () -> String) {
    if (isDebug) System.err.println(msg())
  }

  private fun debug(a: LongArray) {
    debug { a.joinToString(" ") }
  }

  private fun debug(a: IntArray) {
    debug { a.joinToString(" ") }
  }

  private fun debug(a: BooleanArray) {
    debug { a.map { if (it) 1 else 0 }.joinToString("") }
  }

  private fun debugDim(A: Array<LongArray>) {
    if (isDebug) {
      for (a in A) {
        debug(a)
      }
    }
  }

  /**
   * 勝手にimport消されるのを防ぎたい
   */
  private fun hoge() {
    min(1, 2)
    max(1, 2)
    abs(-10)
  }
}

fun <A, B> pair(a: A, b: B) = RPair(a, b)
data class RPair<A, B>(val _1: A, val _2: B)

fun main() {
  val out = java.io.PrintWriter(System.out)
  Solver(System.`in`, out).solve()
  out.flush()
}


fun main() {
    val (p1, t1) = readln().split(' ').let { (p, t) -> p.toInt() to t.toLong() }
    val (p2, t2) = readln().split(' ').let { (p, t) -> p.toInt() to t.toLong() }
    val (h, s) = readln().split(' ').let { (h, s) -> h.toInt() to s.toLong() }
    val minTime = LongArray(h + 1){Long.MAX_VALUE shr 1}.also { it[0] = 0L }
    for (c1 in 1 .. h) {
        val time = t1 * c1
        val c2 = time / t2
        val damage = p1 * c1 + p2 * c2 - s * if (c2 > 0) (c1 + c2 - 1) else (c1 + c2)
        for (i in minTime.indices) {
            val j = minOf(h.toLong(), i + damage).toInt()
            minTime[j] = minOf(minTime[j], minTime[i] + time)
        }
    }
    for (c2 in 1 .. h) {
        val time = t2 * c2
        val c1 = time / t1
        val damage = p1 * c1 + p2 * c2 - s * if (c1 > 0) (c1 + c2 - 1) else (c1 + c2)
        for (i in minTime.indices) {
            val j = minOf(h.toLong(), i + damage).toInt()
            minTime[j] = minOf(minTime[j], minTime[i] + time)
        }
    }
    val result = minTime[h]
    println(result)
}


fun main() {
    fun readInts() = readLine()!!.split(" ").map(String::toInt)

    val numToNumSegments = intArrayOf(6, 2, 5, 5, 4, 5, 6, 3, 7, 6)
    val (a, b) = readInts()
    var sol = 0L
    for (num in a..b) {
        var n = num
        while (n != 0) {
            sol += numToNumSegments[n % 10]
            n /=10
        }
    }
    print(sol)
}


fun main() {
    var (a, b) = readLine()!!.split(' ').map { it.toInt() }
    var count = 0L
    for (i in a..b){
        var digit = i.toString()
        for (i in digit){
            when(i){
                '0'->count+=6
                '1'->count+=2
                '2'->count+=5
                '3'->count+=5
                '4'->count+=4
                '5'->count+=5
                '6'->count+=6
                '7'->count+=3
                '8'->count+=7
                '9'->count+=6
            }
        }
    }
    println(count)
}


import java.util.*

fun main() {

    val scanner = Scanner(System.`in`)

    val w = scanner.nextInt()
    val h = scanner.nextInt()

    var ans: Long = 0

    for (x in 0..w) {
        for (y in 0..h) {
            if (x % 2 == 0 && y % 2 == 0 && x > 0 && y > 0) {
                ans += (w - x + 1) * (h - y + 1)
            }
        }
    }

    println(ans)

}


import java.util.Scanner

fun main(args: Array<String>) {
    val scanner = Scanner(System.`in`)
    val n = scanner.nextLine()
    println("25")
}


fun main() {
    val r = System.`in`.bufferedReader()
    val s = StringBuilder()
    var n = r.readLine()!!.toLong()
    var base = 5
    var ans = 1
    //val l = r.readLine()!!.split(" ").map { it.toInt() }
    while (n > 0) {
        if (n%2 == 1L){
            ans  = ans * base %100
        }
        base = base * base % 100
        n /= 2
    }
    println(ans)
}


import java.util.*
import java.io.*
import java.lang.Math.*

private fun exit(msg: String) {
    println(msg)
    System.exit(0)
}
private fun exit(msg: Int) = exit(""+msg)

fun main(args: Array<String>) {
    val scan = object {
        private val reader = BufferedReader(InputStreamReader(System.`in`))
        private var tokenizer: StringTokenizer? = null

        internal operator fun next(): String {
            var t = tokenizer
            while (t == null || !t.hasMoreTokens()) {
                t = StringTokenizer(line())
            }
            return t.nextToken().apply { tokenizer = t }
        }

        internal fun int(): Int = next().toInt()
        internal fun long(): Long = next().toLong()
        internal fun double() = next().toDouble()

        internal fun line() = reader.readLine()

    }

    val n = scan.long()
    println("25")
}


import kotlin.math.abs
import kotlin.math.min

fun main(args: Array<String>) {
    readLine()
    println("25")
}


fun main() {
    fun readInt() = readLine()!!.toInt()
    fun readInts() = readLine()!!.split(" ").map(String::toInt)

    val n = readInt()
    if (n and 1 == 0) return print("No")
    val arr = readInts()
    print(if (arr.first() and 1 == 1 && arr.last() and 1 == 1) "Yes" else "No")
}


fun main() {
    var n = readLine()!!.toInt()
    var list = readLine()!!.split(' ').map { it.toInt() }
    if (list.size  % 2 == 1 && list[0] % 2 == 1 && list[n - 1] % 2 == 1) {
        println("YES")
    } else {
        println("NO")
    }
}


import java.io.BufferedReader
import java.io.FileReader
import java.io.InputStreamReader

val ONLINE = System.getProperty("ONLINE_JUDGE") != null
val inp = BufferedReader(if (ONLINE) InputStreamReader(System.`in`) else FileReader("in.txt"))

inline fun readTokens() = inp.readLine()!!.split(' ')
inline fun readInts() = readTokens().map { it.toInt() }
inline fun readInt() = inp.readLine()!!.toInt()
inline fun readLine() = inp.readLine()!!

fun main(args: Array<String>) {
    val n=readInt()
    val a=readInts().toIntArray()
    if((a[0]%2==1)&&(a[n-1]%2==1)&&(n%2==1)){
        println("Yes")
    }else{
        println("No")
    }
}


fun main(args: Array<String>) {
    val a = readLine()!!.split(" ").map{ it.toInt() }.toMutableList()
    if (a[0] * 3 <= a[1]) {
        print(0)
    } else {
        print(a[0] * 3 - a[1])
    }
}


import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.*

var a = 0
var b = 0
var c = 0

fun main(args: Array<String>) {
    val reader = Reader()
    for (i in 1..3) {
        val next = reader.next()
        if (next[1] == '>') {
            isGreater(next[0])
        } else {
            isGreater(next[2])
        }
    }
    if (a == 1 && b == 1 && c == 1)
        print("Impossible")
    else
        for (i in 0..2) {
            if (a == i)
                print('A')
            if (b == i)
                print('B')
            if (c == i)
                print('C')
        }
}

fun isGreater(char: Char) {
    if (char == 'A') a++ else if (char == 'B') b++ else c++
}

internal class Reader {
    var br: BufferedReader
    var st: StringTokenizer? = null

    init {
        br = BufferedReader(InputStreamReader(System.`in`))
    }

    operator fun next(): String {
        while (st == null || !st!!.hasMoreElements()) {
            try {
                st = StringTokenizer(br.readLine())
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
        return st!!.nextToken()
    }

    fun nextInt(): Int {
        return Integer.parseInt(next())
    }

    fun nextLong(): Long {
        return java.lang.Long.parseLong(next())
    }

    fun nextDouble(): Double {
        return java.lang.Double.parseDouble(next())
    }

    fun nextLine(): String {
        var str = ""
        try {
            str = br.readLine()
        } catch (e: IOException) {
            e.printStackTrace()
        }

        return str
    }
}


fun main()
{
    var mp =HashMap<Char,Int >()
    mp.put('A',0)
    mp.put('B',0)
    mp.put('C',0)
    var s:String
    s= readLine()!!.toString()
            if(s[1]=='>')
            mp.set(s[0],+1)else
            mp.set(s[2],+1)
    s= readLine()!!.toString()
    if(s[1]=='>')
    {
        if(mp.get(s[0])==1)
            mp.set(s[0],+2)else
            mp.set(s[0],1)
    }else
    {
        if(mp.get(s[2])==1)
            mp.set(s[2],+2)else
            mp.set(s[2],1)
    }
    s= readLine()!!.toString()
    if(s[1]=='>')
    {
        if(mp.get(s[0])==1)
            mp.set(s[0],+2)else
            mp.set(s[0],1)
    }else
    {
        if(mp.get(s[2])==1)
            mp.set(s[2],+2)else
            mp.set(s[2],1)
    }
    val result = mp.toList().sortedBy { (_, value) -> value}.toMap()
    if(mp['A']==1&&mp['B']==1&&mp['C']==1)
        print("Impossible") else
    {
        for (entry in result) {
            print(entry.key)
        }
    }
}


fun main(args: Array<String>) {
    val a = Array(3) {readLine()!!}
    println(listOf("ABC", "ACB", "BAC", "BCA", "CAB", "CBA").filter {
        s -> a.filter { x -> (s.indexOf(x[0]) > s.indexOf(x[2])) == (x[1] == '<')}.isEmpty()
    }.firstOrNull() ?: "Impossible")
}


fun main(args: Array<String>) {
	val a = Array(3) {readLine()!!}
	println(listOf("ABC", "ACB", "BAC", "BCA", "CAB", "CBA").firstOrNull {
			s -> a.all {x -> (s.indexOf(x[0]) > s.indexOf(x[2])) != (x[1] == '<')}
	} ?: "Impossible")
}


fun main() {
    var (hour, minutes) = readLine()!!.split(":").map(String::toInt)
    do {
        minutes++
        if (minutes == 60) {
            minutes = 0
            hour++
            if (hour == 24) hour = 0
        }
    } while (String.format("%02d", hour) != String.format("%02d", minutes).reversed())
    print("${String.format("%02d", hour)}:${String.format("%02d", minutes)}")
}


import java.io.BufferedInputStream
import java.io.File
import java.io.PrintWriter
import kotlin.system.measureTimeMillis

inline fun TIME(f:()->Unit){
    val t = measureTimeMillis(){
        f()
    }
    println("$t ms")
}

object IO{
    private const val BS = 1 shl 16
    private const val NC = 0.toChar()
    private val buf = ByteArray(BS)
    private var bId = 0
    private var size = 0
    private var c = NC

    var warningActive = true
    var fakein = StringBuilder()

    private var IN: BufferedInputStream = BufferedInputStream(System.`in`, BS)
    val OUT: PrintWriter = PrintWriter(System.out)

    private val char: Char
        get() {
            while (bId == size) {
                size = IN.read(buf) // no need for checked exceptions
                if (size == -1) return NC
                bId = 0
            }
            return buf[bId++].toChar()
        }

    fun nextInt(): Int {
        var neg = false
        if (c == NC) c = char
        while (c < '0' || c > '9') {
            if (c == '-') neg = true
            c = char
        }
        var res = 0
        while (c in '0'..'9') {
            res = (res shl 3) + (res shl 1) + (c - '0')
            c = char
        }
        return if (neg) -res else res
    }
    fun nextLong(): Long {
        var neg = false
        if (c == NC) c = char
        while (c < '0' || c > '9') {
            if (c == '-') neg = true
            c = char
        }
        var res = 0L
        while (c in '0'..'9') {
            res = (res shl 3) + (res shl 1) + (c - '0')
            c = char
        }
        return if (neg) -res else res
    }
    fun nextString():String{
        val ret = StringBuilder()
        while (true){
            c = char
            if(!isWhitespace(c)){ break}
        }
        ret.append(c)
        while (true){
            c = char
            if(isWhitespace(c)){ break}
            ret.append(c)
        }
        return ret.toString()
    }
    fun isWhitespace(c:Char):Boolean{
        return c == ' ' || c == '\n' || c == '\r' || c == '\t'
    }
    fun rerouteInput(){
        if(warningActive){
            put("You forgot to disable tests you digital dummy!")
            println("You forgot to disable tests you digital dummy!")
            warningActive = false
        }
        val S = fakein.toString()
        println("New Case ")
        println(S.take(80))
        println("...")
        fakein.clear()
        IN = BufferedInputStream(S.byteInputStream(),BS)
    }
    fun takeFile(name:String){
        IN = BufferedInputStream(File(name).inputStream(),BS)
    }
}
fun put(aa:Any){ IO.OUT.println(aa)}
fun done(){ IO.OUT.close() }
fun share(aa:Any){
    if(aa is IntArray){IO.fakein.append(aa.joinToString(" "))}
    else if(aa is LongArray){IO.fakein.append(aa.joinToString(" "))}
    else if(aa is List<*>){IO.fakein.append(aa.toString())}
    else{IO.fakein.append(aa.toString())}
    IO.fakein.append("\n")
}

val getint:Int get() = IO.nextInt()
val getlong:Long get() = IO.nextLong()
val getstr:String get() = IO.nextString()
fun getline(n:Int):IntArray{
    return IntArray(n){getint}
}
fun getlineL(n:Int):LongArray{
    return LongArray(n){getlong}
}
fun getbinary(n:Int, asTrue:Char):BooleanArray{
    val str = getstr
    return BooleanArray(n){str[it] == asTrue}
}

val List<Char>.ret:String
get() = this.joinToString("")
var dmark = -1
infix fun Any.dei(a:Any){
    //does not stand for anything it is just easy to type, have to be infix because kotlin does not have custom prefix operators
    dmark++
    var str = "<${dmark}>   "
    debug()
    if(this is String){ str += this
    }else if(this is Int){ str += this.toString()
    }else if(this is Long){ str += this.toString()
    }else{ str += this.toString()}
    if(a is List<*>){ println("$str : ${a.joinToString(" ")}")
    }else if(a is IntArray){ println("$str : ${a.joinToString(" ")}")
    }else if(a is LongArray){ println("$str : ${a.joinToString(" ")}")
    }else if(a is BooleanArray){ println("$str :${a.map{if(it)'1' else '0'}.joinToString(" ")}")
    }else if(a is Array<*>){
        println("$str : ")
        for(c in a){if(c is IntArray){println(c.joinToString(" "))}
        else if(c is LongArray){println(c.joinToString(" "))}
        else if(c is BooleanArray){println(c.map { if(it) '1' else '0' }.joinToString(""))
        }

        }
        println()
    }else{ println("$str : $a")
    }
}
val just = " " // usage: just dei x , where x is the debug variable
fun crash(){
    throw Exception("Bad programme")} // because assertion does not work
fun assert(a:Boolean){
    if(!a){
        throw Exception("Failed Assertion")
    }}
enum class solveMode {
    real, rand, tc
}
object solve{
    var mode:solveMode = solveMode.real
    var tcNum:Int = 0
    var rand:()->Unit = {}
    var TC:MutableMap<Int,()->Unit> = mutableMapOf()
    var answersChecked = 0
    var tn:Long = 0
    fun cases(onecase:()->Unit){
        val t = if(mode == solveMode.real){if(singleCase) 1 else getint} else if(mode == solveMode.tc){1 } else randCount
        //safety checks
        if(pI != 998_244_353 && pI != 1_000_000_007){
            throw Exception("Modding a wrong prime!")
        }
        if(withBruteForce){
            println("Brute force is active")
        }

        if(t == 1 && mode != solveMode.real){
            tn = System.currentTimeMillis()
        }
        repeat(t){
            if(mode == solveMode.tc){
                TC[tcNum]?.let { it() }
                IO.rerouteInput()
            }else if(mode == solveMode.rand){
                rand()
                IO.rerouteInput()
            }
            onecase()
        }
        if(t == 1 && mode != solveMode.real){
            val dt = System.currentTimeMillis() - tn
            println("Time $dt ms ")
        }
    }
    inline fun singleCase(a:solve.()->Unit){
        val t = if(mode != solveMode.rand){1} else randCount
        repeat(t) { a() }
    }
    fun rand(a:()->Unit){
        this.rand = a
    }
    fun tc(id:Int = 0,a:()->Unit){
        TC[id] = a
    }
    fun usetc(a:Int = 0 ){
        this.tcNum = a
        this.mode = solveMode.tc
    }
    fun userand(){
        this.mode = solveMode.rand
    }
}
inline fun<T> T.alsoBrute(cal:() -> T){
    if(!withBruteForce) return
    val also = cal()
    if(this != also){
        println("Checking failed: Got ${this} Brute ${also}")
        crash()
    }
}
// 1. Modded
const val p = 998244353L
const val pI = p.toInt()
fun Int.adjust():Int{ if(this >= pI){ return this  - pI }else if (this < 0){ return this + pI };return this }
fun Int.snap():Int{ if(this >= pI){return this - pI} else return this}
infix fun Int.modM(b:Int):Int{ return ((this * 1L * b) % pI).toInt() }
infix fun Int.modPlus(b:Int):Int{ val ans = this + b;return if(ans >= pI) ans - pI else ans }
// 2. DP initial values
const val plarge = 1_000_000_727
const val nlarge = -plarge
const val phuge = 2_727_000_000_000_000_000L
const val nhuge = -phuge
// 3. conveniecen conversions
val Boolean.chi:Int get() = if(this) 1 else 0 //characteristic function
val Char.code :Int get() = this.toInt() -  'a'.toInt()
//3. hard to write stuff
fun IntArray.put(i:Int,v:Int){ this[i] = (this[i] + v).adjust() }
val mint:MutableList<Int> get() = mutableListOf<Int>()
val mong:MutableList<Long> get() = mutableListOf<Long>()
//4. more outputs
fun List<Char>.conca():String = this.joinToString("")
val CharArray.conca :String get() = this.joinToString("")
val IntArray.conca :String get() = this.joinToString(" ")
@JvmName("concaInt")
fun List<Int>.conca():String = this.joinToString(" ")
val LongArray.conca:String get() = this.joinToString(" ")
@JvmName("concaLong")
fun List<Long>.conca():String = this.joinToString(" ")
//5. Pair of ints
const val longmask = (1L shl 32) - 1
fun makepair(a:Int, b:Int):Long = (a.toLong() shl 32) xor (longmask and b.toLong()) // remember positev sonly
val Long.first get() = (this ushr 32).toInt()
val Long.second get() = this.toInt()
//6. strings
val String.size get() = this.length
const val randCount = 100

infix fun Int.divCeil(b:Int):Int{
    //Positives numbers only!
    if(this == 0) {
        return 0
    }
    return (this-1)/b + 1
}
infix fun Long.divCeil(b:Long):Long{
    //Positives numbers only!
    if(this == 0L) {
        return 0
    }
    return (this-1)/b + 1
}

infix fun Long.modM(b:Long):Long{
    return (this * b) % p
}
//infix fun Int.modPlus(b:Int):Int{
//    val ans = this + b
//    return if(ans >= pI) ans - pI else ans
//}
infix fun Int.modMinus(b:Int):Int{
    val ans = this - b
    return if(ans < 0) ans + pI else ans
}
infix fun Int.modDivide(b:Int):Int{
    return this modM (b.inverse())
}
fun Int.additiveInverse():Int{
    return if(this == 0) 0 else pI - this
}

fun intPow(x:Int,e:Int,m:Int):Int{
    var X = x
    var E =e
    var Y = 1
    while(E > 0){
        if(E % 2 == 0){
            X = ((1L * X * X) % m).toInt()
            E = E shr 1
        }else{
            Y = ((1L * X * Y) % m).toInt()
            E -= 1
        }
    }
    return Y
}
fun intPowEXP(x:Int,e:Long,m:Int):Int{
    var X = x
    var E =e
    var Y = 1
    while(E > 0){
        if(E % 2 == 0L){
            X = ((1L * X * X) % m).toInt()
            E = E shr 1
        }else{
            Y = ((1L * X * Y) % m).toInt()
            E -= 1
        }
    }
    return Y
}

fun pow(x:Long,e:Long,m:Long):Long{
    var X = x
    var E =e
    var Y = 1L
    while(E > 0){
        if(E % 2 == 0L){
            X = (X * X) % m
            E /= 2
        }else{
            Y = (X * Y) % m
            E -= 1
        }
    }
    return Y
}
fun Long.inverse():Long{
    return pow(this,p-2,p)
}
fun Int.inverse():Int{
    return intPow(this,pI-2,pI)
}
fun min_rem(m:Int, r:Int, c:Int):Int {
    if(c < 1){
        return Int.MIN_VALUE
    }else if(r == 0){
        return 0
    }else{
        val step = m % r
        val mx = ((1L * c * r) /m ).toInt()
        val t = max_rem(r,step,mx)
        return r- t
    }
}
fun max_rem(m:Int, r:Int, c:Int):Int {
    if(r == 0|| c <= m/r){
        return r * c
    }else{
        val step =  m % r
        val mx = ((1L * (c+1) * r )/m).toInt()
        val t = min_rem(r,step,mx)
        return  m - t
    }
}
fun Int.reconstruct():String{
    val num = min_rem(pI,this, 10000)
    val denom = (this modDivide num).inverse()
    return "$num / $denom"
}

//make this int instead
class FACT{
    companion object {
        var store = IntArray(0)
        var invStore = IntArray(0)

        var slowStore:IntArray = IntArray(0)

        fun preCal(upto:Int){
            store = IntArray(upto+1)
            invStore = IntArray(upto + 1 )
            store[0] = 1
            invStore[0] = 1

            for(i in 1..upto) {
                store[i] = store[i-1] modM i
                invStore[i] = invStore[i-1] modM (i.inverse())
            }
        }
        fun choose(n:Int,r:Int):Int{
            if(r < 0 || r > n) return 0
            val a = store[n]
            val b = invStore[n-r]
            val c = invStore[r]
            return (a modM b) modM c
        }

        fun bigChoose(n:Int,r:Int):Int{
            var ret = 1
            for(i in 0 until r){
                ret = ret modM (n - i)
            }
            ret = ret modM (invStore[r])
            return ret
        }

    }
}

fun debug(){}
const val withBruteForce = false
const val singleCase = true
fun main(){
    FACT.preCal(300)
    solve.cases{

        val n = getint
        val k = getint

        //phrases, MAX
        val DP = Array(n){IntArray(k+1)}
        val sum = Array(n){IntArray(k+1)}

        DP[0][0] = FACT.store[n-1]
        for(max in 0..k){
            sum[0][max] = FACT.store[n-1]
        }
//        sum[0][0] = FACT.store[n]

        for(p in 1 until n){
            for(max in 1..k){
                var now = 0
                var totalop = 0
                for(op in p-1 downTo 0 ){
                    totalop += op
                    now = now modPlus (sum[op][max-1] modM FACT.invStore[p-op] modM intPow(k-max+1,totalop,pI))
                }
                DP[p][max] = now
            }
            for(max in 0..k){
                sum[p][max] = DP[p][max]
                if(max > 0){
                    sum[p][max] = sum[p][max-1] modPlus sum[p][max]
                }
            }
        }
        var ret = 0
        for(c in DP.last()){
            ret = ret modPlus c
        }

        put(ret)

    }
    done()
}

/*

3 3

costs are
1,1,2,..,n

1 2 3 3 4 5
1 2 3 3 4 5

1 2
2 1
3 4
4 3
max of hte two things then product

 */


import kotlin.math.max
import kotlin.math.min

val MOD = 1_000_000_007

class BIT(n: Int) {
  private val N =
    if (Integer.highestOneBit(n) == n) n
    else Integer.highestOneBit(n) shl 1

  private val bit = IntArray(N + 1)

  fun sum(i: Int): Int {
    var x = i
    var s = 0
    while(x > 0) {
      s += bit[x]
      x -= x and -x
    }
    return s
  }

  fun add(i: Int, a: Int) {
    var x = i + 1
    while(x <= N) {
      bit[x] += a
      x += x and -x
    }
  }
}

fun main() {
  val (N) = readInts()
  val A = readInts().filter{it > 0}.toIntArray()
  A.sort()
  val win = A.size == 1 ||
      A.size == 2 && calc2(A, N == 2) ||
      A.size == 3 && A[0] xor A[1] != A[2]

  if (win) println("BitLGM")
  else println("BitAryo")
}

fun calc2(A: IntArray, op2: Boolean): Boolean {
  val dp = Array(A[0] + 1) { BooleanArray(A[1] + 1) }
  for (i in 0..A[0]) {
    for (j in 0..A[1]) {
      var win = false
      for (l in 0 until i) {
        if (!dp[l][j]) win = true
      }
      for (l in 0 until j) {
        if (!dp[i][l]) win = true
      }
      if (op2) {
        for (l in 1..min(i, j)) {
          if (!dp[i - l][j - l]) win = true
        }
      }
      dp[i][j] = win
    }
  }
  return dp[A[0]][A[1]]
}

private val isDebug = try {
  // なんか本番でエラーでる
  System.getenv("MY_DEBUG") != null
} catch (t: Throwable) {
  false
}

private fun readLn() = readLine()!!
private fun readStrings() = readLn().split(" ")
private fun readInts() = readStrings().map { it.toInt() }.toIntArray()
private fun readLongs() = readStrings().map { it.toLong() }.toLongArray()
private inline fun debug(msg: () -> String) {
  if (isDebug) System.err.println(msg())
}
private fun debug(a: LongArray) {
  debug{a.joinToString(" ")}
}
private fun debug(a: IntArray) {
  debug{a.joinToString(" ")}
}
private fun debug(a: BooleanArray) {
  debug{a.map{if(it) 1 else 0}.joinToString("")}
}
private fun debugDim(A: Array<LongArray>) {
  if (isDebug) {
    for (a in A) {
      debug(a)
    }
  }
}


@file:Suppress("NOTHING_TO_INLINE", "EXPERIMENTAL_FEATURE_WARNING", "OVERRIDE_BY_INLINE")

import java.io.PrintWriter
import java.util.PriorityQueue
import java.util.SortedMap
import java.util.StringTokenizer
import java.util.TreeMap
import kotlin.math.*
import kotlin.random.*
import kotlin.collections.sort as _sort
import kotlin.collections.sortDescending as _sortDescending
import kotlin.io.println as iprintln

/** @author Spheniscine */
fun main() { _writer.solve(); _writer.flush() }
fun PrintWriter.solve() {
    val r0 = readInt()
    val g0 = readInt()

    var D = ModIntArray(r0 + 1)
    D[r0] = ModInt(1)

    for(h in 1..200000) {
        val Di = ModIntArray(D.size)
        val s = g0 - h * (h-1) / 2 + r0
        var ok = false
        for(r in D.indices) {
            val v = D[r]
            if(v.int == 0) continue
            val g = s - r
            if(r >= h) {
                Di[r-h] += v
                ok = true
            }
            if(g >= h) {
                Di[r] += v
                ok = true
            }
        }
        if(!ok) break
        D = Di
    }

    val ans = D.sum().int

    println(ans)
}

const val BILLION7 = 1e9.toInt() + 7
const val MODINT_BASE = BILLION7
const val MODINT_TOTIENT = MODINT_BASE - 1 // assumes MODINT_BASE is prime

inline infix fun Int.umod(base: Int) = Math.floorMod(this, base)
inline infix fun Long.umod(base: Long) = Math.floorMod(this, base)
inline infix fun Long.umod(base: Int) = Math.floorMod(this, base.toLong()).toInt()

fun Int.mulMod(other: Int, mod: Int) = (toLong() * other).umod(mod)

fun Int.powMod(exponent: Int, mod: Int): Int {
    if(exponent < 0) error("Inverse not implemented")
    var res = 1L
    var e = exponent
    var b = umod(mod).toLong()

    while(e > 0) {
        if(e and 1 == 1) {
            res = res * b % mod
        }
        e = e shr 1
        b = b * b % mod
    }
    return res.toInt()
}

inline fun Int.toModInt() = ModInt(this umod MODINT_BASE)
inline fun Long.toModInt() = ModInt(this umod MODINT_BASE)

/** note: Only use constructor for int within modulo range, otherwise use toModInt **/
inline class ModInt(val int: Int) {
    companion object {
        /** can't seem to make these private or inlined without causing compiler issues */
        @JvmField val _invMemo = HashMap<ModInt, ModInt>()
        fun _invMemoized(m: ModInt) = _invMemo.getOrPut(m) { m.inv_unmemoized() }
    }

    operator fun plus(other: ModInt) = // MODINT_BASE < 2^30
        (int + other.int).let { if(it >= MODINT_BASE) ModInt(it - MODINT_BASE) else ModInt(it) }
    inline operator fun plus(other: Int) = plus(other.toModInt())
    operator fun inc() = if(int == MODINT_BASE - 1) ModInt(0) else ModInt(int + 1)

    operator fun minus(other: ModInt) =
        (int - other.int).let { if(it < 0) ModInt(it + MODINT_BASE) else ModInt(it) }
    inline operator fun minus(other: Int) = minus(other.toModInt())
    operator fun dec() = if(int == 0) ModInt(MODINT_BASE - 1) else ModInt(int - 1)
    operator fun unaryMinus() = if(int == 0) this else ModInt(MODINT_BASE - int)

    inline operator fun times(other: ModInt) = times(other.int)
    inline operator fun times(other: Int) = ModInt(int.mulMod(other, MODINT_BASE))

    fun pow(exponent: Int): ModInt {
        val e = if(exponent < 0) {
            require(int != 0) { "Can't invert/divide by 0" }
            exponent umod MODINT_TOTIENT
        } else exponent
        return ModInt(int.powMod(e, MODINT_BASE))
    }

    fun pow(exponent: Long) = if(int == 0) when {
        exponent > 0 -> this
        exponent == 0L -> ModInt(1)
        else -> error("Can't invert/divide by 0")
    } else pow(exponent umod MODINT_TOTIENT)

    inline fun inverse() = inv_memoized() /** NOTE: Change if necessary */

    fun inv_unmemoized(): ModInt {
        require(int != 0) { "Can't invert/divide by 0" }
        return pow(MODINT_TOTIENT - 1)
    }
    inline fun inv_memoized() = _invMemoized(this)

    operator fun div(other: ModInt) = times(other.inverse())
    inline operator fun div(other: Int) = div(other.toModInt())

    override inline fun toString() = int.toString()
}

inline class ModIntArray(val intArray: IntArray): Collection<ModInt> {
    inline operator fun get(i: Int) = ModInt(intArray[i])
    inline operator fun set(i: Int, v: ModInt) { intArray[i] = v.int }

    override inline val size: Int get() = intArray.size
    inline val lastIndex get() = intArray.lastIndex
    inline val indices get() = intArray.indices

    override inline fun contains(element: ModInt): Boolean = element.int in intArray

    override fun containsAll(elements: Collection<ModInt>): Boolean = elements.all(::contains)

    override inline fun isEmpty(): Boolean = intArray.isEmpty()

    override fun iterator(): Iterator<ModInt> = object: Iterator<ModInt> {
        var index = 0
        override fun hasNext(): Boolean = index < size
        override fun next(): ModInt = get(index++)
    }

    fun copyOf(newSize: Int) = ModIntArray(intArray.copyOf(newSize))
    fun copyOf() = copyOf(size)
}
fun ModIntArray(capacity: Int) = ModIntArray(IntArray(capacity))
inline fun ModIntArray(capacity: Int, init: (Int) -> ModInt) =
    ModIntArray(IntArray(capacity) { init(it).int })

fun ModIntArray.sum() = indices.sumByModInt(::get)
fun ModIntArray.product() = indices.productByModInt(::get)

inline fun <T> Iterable<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Iterable<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
inline fun <T> Sequence<T>.sumByModInt(func: (T) -> ModInt) = fold(ModInt(0)) { acc, t -> acc + func(t) }
inline fun <T> Sequence<T>.productByModInt(func: (T) -> ModInt) = fold(ModInt(1)) { acc, t -> acc * func(t) }
fun Iterable<ModInt>.sum() = sumByModInt { it }
fun Sequence<ModInt>.sum() = sumByModInt { it }
fun Iterable<ModInt>.product() = productByModInt { it }
fun Sequence<ModInt>.product() = productByModInt { it }

/** IO code start */
//@JvmField val INPUT = File("input.txt").inputStream()
//@JvmField val OUTPUT = File("output.txt").outputStream()
@JvmField val INPUT = System.`in`
@JvmField val OUTPUT = System.out

@JvmField val _reader = INPUT.bufferedReader()
fun readLine(): String? = _reader.readLine()
fun readLn() = _reader.readLine()!!
@JvmField var _tokenizer: StringTokenizer = StringTokenizer("")
fun read(): String {
    while (_tokenizer.hasMoreTokens().not()) _tokenizer = StringTokenizer(_reader.readLine() ?: return "", " ")
    return _tokenizer.nextToken()
}
fun readInt() = read().toInt()
fun readDouble() = read().toDouble()
fun readLong() = read().toLong()
fun readStrings(n: Int) = List(n) { read() }
fun readLines(n: Int) = List(n) { readLn() }
fun readInts(n: Int) = List(n) { read().toInt() }
fun readIntArray(n: Int) = IntArray(n) { read().toInt() }
fun readDoubles(n: Int) = List(n) { read().toDouble() }
fun readDoubleArray(n: Int) = DoubleArray(n) { read().toDouble() }
fun readLongs(n: Int) = List(n) { read().toLong() }
fun readLongArray(n: Int) = LongArray(n) { read().toLong() }

@JvmField val _writer = PrintWriter(OUTPUT, false)

/** shuffles and sort overrides to avoid quicksort attacks */
private inline fun <T> _shuffle(rnd: Random, get: (Int) -> T, set: (Int, T) -> Unit, size: Int) {
    // Fisher-Yates shuffle algorithm
    for (i in size - 1 downTo 1) {
        val j = rnd.nextInt(i + 1)
        val temp = get(i)
        set(i, get(j))
        set(j, temp)
    }
}

@JvmField var _random: Random? = null
val random get() = _random ?: Random(0x594E215C123 * System.nanoTime()).also { _random = it }

fun IntArray.shuffle(rnd: Random = random) = _shuffle(rnd, ::get, ::set, size)
fun IntArray.sort() { shuffle(); _sort() }
fun IntArray.sortDescending() { shuffle(); _sortDescending() }

fun LongArray.shuffle(rnd: Random = random) = _shuffle(rnd, ::get, ::set, size)
fun LongArray.sort() { shuffle(); _sort() }
fun LongArray.sortDescending() { shuffle(); _sortDescending() }

fun DoubleArray.shuffle(rnd: Random = random) = _shuffle(rnd, ::get, ::set, size)
fun DoubleArray.sort() { shuffle(); _sort() }
fun DoubleArray.sortDescending() { shuffle(); _sortDescending() }

fun CharArray.shuffle(rnd: Random = random) = _shuffle(rnd, ::get, ::set, size)
inline fun CharArray.sort() { _sort() }
inline fun CharArray.sortDescending() { _sortDescending() }

inline fun <T: Comparable<T>> Array<out T>.sort() = _sort()
inline fun <T: Comparable<T>> Array<out T>.sortDescending() = _sortDescending()
inline fun <T: Comparable<T>> MutableList<out T>.sort() = _sort()
inline fun <T: Comparable<T>> MutableList<out T>.sortDescending() = _sortDescending()

fun `please stop removing these imports IntelliJ`() {
    iprintln(max(1, 2))
}