import macros macro Please(x): untyped = nnkStmtList.newTree() Please use Nim-ACL Please use Nim-ACL Please use Nim-ACL #[ include atcoder/extra/header/chaemon_header ]# when not declared ATCODER_CHAEMON_HEADER_HPP: const ATCODER_CHAEMON_HEADER_HPP* = 1 {.hints:off warnings:off assertions:on optimization:speed.} when declared(DO_CHECK): when DO_CHECK: static: echo "check is on" {.checks:on.} else: static: echo "check is off" {.checks:off.} else: static: echo "check is on" {.checks:on.} import std/algorithm as algorithm_lib import std/sequtils as sequtils_lib import std/macros as macros_lib import std/math as math_lib import std/sets as sets_lib import std/tables as tables_lib import std/strutils as strutils_lib import std/strformat as strformat_lib import std/options as options_lib import std/bitops as bitops_lib import std/streams as streams_lib import std/deques as deques_lib #[ import atcoder/extra/forward_compatibility/internal_sugar ]# when not declared ATCODER_INTERNAL_SUGAR_HPP: const ATCODER_INTERNAL_SUGAR_HPP* = 1 import std/macros import std/typetraits proc checkPragma(ex, prag: var NimNode) = # since (1, 3): block: if ex.kind == nnkPragmaExpr: prag = ex[1] if ex[0].kind == nnkPar and ex[0].len == 1: ex = ex[0][0] else: ex = ex[0] proc createProcType(p, b: NimNode): NimNode {.compileTime.} = result = newNimNode(nnkProcTy) var formalParams = newNimNode(nnkFormalParams).add(b) p = p prag = newEmptyNode() checkPragma(p, prag) case p.kind of nnkPar, nnkTupleConstr: for i in 0 ..< p.len: let ident = p[i] var identDefs = newNimNode(nnkIdentDefs) case ident.kind of nnkExprColonExpr: identDefs.add ident[0] identDefs.add ident[1] else: identDefs.add newIdentNode("i" & $i) identDefs.add(ident) identDefs.add newEmptyNode() formalParams.add identDefs else: var identDefs = newNimNode(nnkIdentDefs) identDefs.add newIdentNode("i0") identDefs.add(p) identDefs.add newEmptyNode() formalParams.add identDefs result.add formalParams result.add prag macro `=>`*(p, b: untyped): untyped = ## Syntax sugar for anonymous procedures. ## It also supports pragmas. var params = @[ident"auto"] name = newEmptyNode() kind = nnkLambda pragma = newEmptyNode() p = p checkPragma(p, pragma) if p.kind == nnkInfix and p[0].kind == nnkIdent and p[0].eqIdent"->": params[0] = p[2] p = p[1] checkPragma(p, pragma) # check again after -> transform # since (1, 3): block: # if p.kind == nnkCall: if p.kind in {nnkCall, nnkObjConstr}: # foo(x, y) => x + y kind = nnkProcDef name = p[0] let newP = newNimNode(nnkPar) for i in 1..": var procTy = createProcType(c[1], c[2]) params[0] = procTy[0][0] for i in 1 ..< procTy[0].len: params.add(procTy[0][i]) else: error("Expected proc type (->) got (" & c[0].strVal & ").", c) break else: error("Incorrect procedure parameter list.", c) params.add(identDefs) of nnkIdent: var identDefs = newNimNode(nnkIdentDefs) identDefs.add(p) identDefs.add(ident"auto") identDefs.add(newEmptyNode()) params.add(identDefs) else: error("Incorrect procedure parameter list.", p) result = newProc(body = b, params = params, pragmas = pragma, name = name, procType = kind) macro `->`*(p, b: untyped): untyped = result = createProcType(p, b) macro dump*(x: untyped): untyped = let s = x.toStrLit let r = quote do: debugEcho `s`, " = ", `x` return r # TODO: consider exporting this in macros.nim proc freshIdentNodes(ast: NimNode): NimNode = # Replace NimIdent and NimSym by a fresh ident node # see also https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458 proc inspect(node: NimNode): NimNode = case node.kind: of nnkIdent, nnkSym: result = ident($node) of nnkEmpty, nnkLiterals: result = node else: result = node.kind.newTree() for child in node: result.add inspect(child) result = inspect(ast) macro capture*(locals: varargs[typed], body: untyped): untyped = var params = @[newIdentNode("auto")] let locals = if locals.len == 1 and locals[0].kind == nnkBracket: locals[0] else: locals for arg in locals: if arg.strVal == "result": error("The variable name cannot be `result`!", arg) params.add(newIdentDefs(ident(arg.strVal), freshIdentNodes getTypeInst arg)) result = newNimNode(nnkCall) result.add(newProc(newEmptyNode(), params, body, nnkProcDef)) for arg in locals: result.add(arg) #[ import atcoder/extra/forward_compatibility/internal_underscored_calls ]# when not declared ATCODER_INTERNAL_UNDERSCORED_CALLS_HPP: const ATCODER_INTERNAL_UNDERSCORED_CALLS_HPP* = 1 import macros proc underscoredCall(n, arg0: NimNode): NimNode = proc underscorePos(n: NimNode): int = for i in 1 ..< n.len: if n[i].eqIdent("_"): return i return 0 if n.kind in nnkCallKinds: result = copyNimNode(n) result.add n[0] let u = underscorePos(n) for i in 1..u-1: result.add n[i] result.add arg0 for i in u+1..n.len-1: result.add n[i] elif n.kind in {nnkAsgn, nnkExprEqExpr}: var field = n[0] if n[0].kind == nnkDotExpr and n[0][0].eqIdent("_"): # handle _.field = ... field = n[0][1] result = newDotExpr(arg0, field).newAssignment n[1] else: # handle e.g. 'x.dup(sort)' result = newNimNode(nnkCall, n) result.add n result.add arg0 proc underscoredCalls*(result, calls, arg0: NimNode) = expectKind calls, {nnkArgList, nnkStmtList, nnkStmtListExpr} for call in calls: if call.kind in {nnkStmtList, nnkStmtListExpr}: underscoredCalls(result, call, arg0) else: result.add underscoredCall(call, arg0) discard macro dup*[T](arg: T, calls: varargs[untyped]): T = result = newNimNode(nnkStmtListExpr, arg) let tmp = genSym(nskVar, "dupResult") result.add newVarStmt(tmp, arg) underscoredCalls(result, calls, tmp) result.add tmp proc transLastStmt(n, res, bracketExpr: NimNode): (NimNode, NimNode, NimNode) = # Looks for the last statement of the last statement, etc... case n.kind of nnkIfExpr, nnkIfStmt, nnkTryStmt, nnkCaseStmt: result[0] = copyNimTree(n) result[1] = copyNimTree(n) result[2] = copyNimTree(n) for i in ord(n.kind == nnkCaseStmt)..= 1: (result[0][^1], result[1][^1], result[2][^1]) = transLastStmt(n[^1], res, bracketExpr) of nnkTableConstr: result[1] = n[0][0] result[2] = n[0][1] if bracketExpr.len == 1: bracketExpr.add([newCall(bindSym"typeof", newEmptyNode()), newCall( bindSym"typeof", newEmptyNode())]) template adder(res, k, v) = res[k] = v result[0] = getAst(adder(res, n[0][0], n[0][1])) of nnkCurly: result[2] = n[0] if bracketExpr.len == 1: bracketExpr.add(newCall(bindSym"typeof", newEmptyNode())) template adder(res, v) = res.incl(v) result[0] = getAst(adder(res, n[0])) else: result[2] = n if bracketExpr.len == 1: bracketExpr.add(newCall(bindSym"typeof", newEmptyNode())) template adder(res, v) = res.add(v) result[0] = getAst(adder(res, n)) macro collect*(init, body: untyped): untyped = # analyse the body, find the deepest expression 'it' and replace it via # 'result.add it' let res = genSym(nskVar, "collectResult") expectKind init, {nnkCall, nnkIdent, nnkSym} let bracketExpr = newTree(nnkBracketExpr, if init.kind == nnkCall: init[0] else: init) let (resBody, keyType, valueType) = transLastStmt(body, res, bracketExpr) if bracketExpr.len == 3: bracketExpr[1][1] = keyType bracketExpr[2][1] = valueType else: bracketExpr[1][1] = valueType let call = newTree(nnkCall, bracketExpr) if init.kind == nnkCall: for i in 1 ..< init.len: call.add init[i] result = newTree(nnkStmtListExpr, newVarStmt(res, call), resBody, res) discard # import std/sugar #[ import atcoder/extra/other/reader ]# when not declared ATCODER_READER_HPP: const ATCODER_READER_HPP* = 1 import streams import strutils import sequtils # proc scanf*(formatstr: cstring){.header: "", varargs.} #proc getchar(): char {.header: "", varargs.} # proc nextInt*(): int = scanf("%lld",addr result) # proc nextFloat*(): float = scanf("%lf",addr result) proc nextString*(f:auto = stdin): string = var get = false result = "" while true: let c = f.readChar #doassert c.int != 0 if c.int > ' '.int: get = true result.add(c) elif get: return proc nextInt*(f:auto = stdin): int = parseInt(f.nextString) proc nextFloat*(f:auto = stdin): float = parseFloat(f.nextString) # proc nextString*():string = stdin.nextString() proc toStr*[T](v:T):string = proc `$`[T](v:seq[T]):string = v.mapIt($it).join(" ") return $v proc print0*(x: varargs[string, toStr]; sep:string):string{.discardable.} = result = "" for i,v in x: if i != 0: addSep(result, sep = sep) add(result, v) result.add("\n") stdout.write result var print*:proc(x: varargs[string, toStr]) print = proc(x: varargs[string, toStr]) = discard print0(@x, sep = " ") discard #[ import atcoder/extra/other/cfor ]# when not declared ATCODER_CFOR_HPP: import std/macros const ATCODER_CFOR_HPP* = 1 macro For*(preLoop, condition, postLoop, body:untyped):NimNode = var preLoop = if preLoop.repr == "()": ident("discard") else: preLoop condition = if condition.repr == "()": ident("true") else: condition postLoop = if postLoop.repr == "()": ident("discard") else: postLoop quote do: `preLoop` var start_cfor {.gensym.} = true while true: if start_cfor: start_cfor = false else: `postLoop` if not `condition`: break `body` template cfor*(preLoop, condition, postLoop, body:untyped):NimNode = For(preLoop, condition, postLoop, body) discard #[ import atcoder/extra/other/sliceutils ]# when not declared ATCODER_SLICEUTILS_HPP: const ATCODER_SLICEUTILS_HPP* = 1 proc index*[T](a:openArray[T]):Slice[int] = a.low..a.high type ReversedSlice[T] = distinct Slice[T] type StepSlice[T] = object s:Slice[T] d:T proc rev*[T](p:Slice[T]):ReversedSlice[T] = ReversedSlice[T](p) iterator items*(n:int):int = (for i in 0..= Slice[T](p).a: var i = Slice[T](p).b while true: yield i if i == Slice[T](p).a:break i.dec proc `>>`*[T](s:Slice[T], d:T):StepSlice[T] = assert d != 0 StepSlice[T](s:s, d:d) proc `<<`*[T](s:Slice[T], d:T):StepSlice[T] = assert d != 0 StepSlice[T](s:s, d: -d) proc low*[T](s:StepSlice[T]):T = s.s.a proc high*[T](s:StepSlice[T]):T = let p = s.s.b - s.s.a if p < 0: return s.low - 1 let d = abs(s.d) return s.s.a + (p div d) * d iterator items*[T](p:StepSlice[T]):T = assert p.d != 0 if p.s.a <= p.s.b: if p.d > 0: var i = p.low let h = p.high while i <= h: yield i if i == h: break i += p.d else: var i = p.high let l = p.low while i >= l: yield i if i == l: break i += p.d proc `[]`*[T:SomeInteger, U](a:openArray[U], s:Slice[T]):seq[U] = for i in s:result.add(a[i]) proc `[]=`*[T:SomeInteger, U](a:var openArray[U], s:StepSlice[T], b:openArray[U]) = var j = 0 for i in s: a[i] = b[j] j.inc discard #[ import atcoder/extra/other/assignment_operator ]# when not declared ATCODER_ASSIGNMENT_OPERATOR_HPP: import std/macros import std/strformat const ATCODER_ASSIGNMENT_OPERATOR_HPP* = 1 proc `max=`*[S, T](a: var S, b: T):bool {.discardable.} = return if a < b: a = b; true else: false proc `min=`*[S, T](a: var S, b: T):bool {.discardable.} = return if a > b: a = b; true else: false template `>?=`*(x,y:typed):bool = x.max= y template `>`, `%`, `//`, `&`, `|`, `^`) discard #[ import atcoder/extra/other/inf ]# when not declared ATCODER_INF_HPP: const ATCODER_INF_HPP* = 1 import sequtils template inf*(T:typedesc): untyped = when T is SomeFloat: T(Inf) elif T is SomeInteger: T.high div 2 else: static: assert(false) template infRepr*[T](x:T):string = when T is seq or T is array: "@[" & x.mapIt(it.infRepr).join(", ") & "]" elif x is SomeInteger or x is SomeFloat: if x >= T.inf: "inf" elif x <= -T.inf: "-inf" else: $x else: $x proc `∞`*(T:typedesc):T = T.inf proc `*!`*[T:SomeInteger](a, b:T):T = if a == T(0) or b == T(0): return T(0) var sgn = T(1) if a < T(0): sgn = -sgn if b < T(0): sgn = -sgn let a = abs(a) let b = abs(b) if b > T.inf div a: result = T.inf else: result = min(T.inf, a * b) result *= sgn proc `+!`*[T:SomeInteger](a, b:T):T = result = a + b result = min(T.inf, result) result = max(-T.inf, result) proc `-!`*[T:SomeInteger](a, b:T):T = result = a - b result = min(T.inf, result) result = max(-T.inf, result) discard #[ import atcoder/extra/other/warlus_operator ]# when not declared ATCODER_CHAEMON_WARLUS_OPERATOR_HPP: const ATCODER_CHAEMON_WARLUS_OPERATOR_HPP* = 1 import macros proc discardableId*[T](x: T): T {.discardable.} = x proc warlusImpl(x, y:NimNode):NimNode = return quote do: when declaredInScope(`x`): `x` = `y` else: var `x` = `y` macro `:=`*(x, y: untyped): untyped = result = newStmtList() if x.kind == nnkCurly: for i,xi in x: result.add warlusImpl(xi, y) elif x.kind == nnkPar: for i,xi in x: result.add warlusImpl(xi, y[i]) else: result.add warlusImpl(x, y) result.add quote do: discardableId(`x`) discard #[ import atcoder/extra/other/seq_array_utils ]# when not declared ATCODER_SEQ_ARRAY_UTILS: const ATCODER_SEQ_ARRAY_UTILS* = 1 import std/strformat import std/macros type SeqType = object type ArrayType = object let Seq* = SeqType() Array* = ArrayType() template fill*[T](a:var T, init:untyped) = when T is init.type: a = init else: for x in a.mitems: fill(x, init) template makeSeq*(x:int; init):auto = when init is typedesc: newSeq[init](x) else: var a = newSeq[typeof(init, typeofProc)](x) a.fill(init) a template makeArray*(x:int or Slice[int]; init):auto = var v:array[x, init.type] v macro `[]`*(x:ArrayType or SeqType, args:varargs[untyped]):auto = var a:string if $x == "Seq" and args.len == 1 and args[0].kind != nnkExprColonExpr: a = fmt"newSeq[{args[0].repr}]()" else: let tail = args[^1] assert tail.kind == nnkExprColonExpr, "Wrong format of tail" let args = args[0 .. ^2] & tail[0] init = tail[1] a = fmt"{init.repr}" if $x == "Array": for i in countdown(args.len - 1, 0): a = fmt"makeArray({args[i].repr}, {a})" a = fmt"{'\n'}block:{'\n'} var a = {a}{'\n'} when {init.repr} isnot typedesc:{'\n'} a.fill({init.repr}){'\n'} a" elif $x == "Seq": for i in countdown(args.len - 1, 0): a = fmt"makeSeq({args[i].repr}, {a})" a = fmt"{'\n'}block:{'\n'} {a}" else: assert(false) parseStmt(a) discard #[ include atcoder/extra/other/debug ]# when not declared ATCODER_DEBUG_HPP: const ATCODER_DEBUG_HPP* = 1 import macros import strformat import terminal #[ import atcoder/extra/other/inf ]# macro debugImpl*(n:varargs[untyped]): untyped = # var a = "stderr.write " var a = "" # a.add "setForegroundColor fgYellow\n" # a.add "stdout.write " # a.add "stderr.write " a.add "styledWriteLine stderr, fgYellow, " for i,x in n: if x.kind == nnkStrLit: a &= fmt"{x.repr} " else: a &= fmt""" "{x.repr} = ", {x.repr}.infRepr """ if i < n.len - 1: a.add(""", ", ",""") # a.add(", \"\\n\"") a.add "\n" # a.add "resetAttributes()" parseStmt(a) template debug*(n: varargs[untyped]): untyped = const EVAL = when declared DEBUG: DEBUG else: false when EVAL: debugImpl(n) discard #[ import atcoder/extra/other/reference ]# when not declared ATCODER_REFERENCE_HPP: const ATCODER_REFERENCE_HPP* = 1 import std/macros import std/strformat template byaddr*(lhs, typ, ex) = when typ is typeof(nil): let tmp = addr(ex) else: let tmp: ptr typ = addr(ex) template lhs: untyped = tmp[] macro `=&`*(lhs, rhs:untyped) = parseStmt(fmt"""byaddr({lhs.repr}, {rhs.repr}.type, {rhs.repr})""") discard #[ import atcoder/extra/other/floatutils ]# when not declared ATCODER_FLOAT_UTILS_HPP: const ATCODER_FLOAT_UTILS_HPP* = 1 import std/math as math_lib_floatutils import std/strutils #[ import atcoder/element_concepts ]# when not declared ATCODER_ELEMENT_CONCEPTS_HPP: const ATCODER_ELEMENT_CONCEPTS_HPP* = 1 proc inv*[T:SomeFloat](a:T):auto = T(1) / a proc init*(self:typedesc[SomeFloat], a:SomeNumber):auto = self(a) type AdditiveGroupElem* = concept x, y, type T x + y x - y -x T(0) type MultiplicativeGroupElem* = concept x, y, type T x * y x / y # x.inv() T(1) type RingElem* = concept x, y, type T x + y x - y -x x * y T(0) T(1) type FieldElem* = concept x, y, type T x + y x - y x * y x / y -x # x.inv() T(0) T(1) type FiniteFieldElem* = concept x, type T T is FieldElem T.mod T.mod() is int x.pow(1000000) type hasInf* = concept x, type T T(Inf) discard #[ import atcoder/extra/other/static_var ]# when not declared ATCODER_STATIC_VAR_HPP: const ATCODER_STATIC_VAR_HPP* = 1 import std/macros import std/strformat macro staticVar*(T:typedesc, body: untyped) = var s = "" for n in body: let name = n[0] let t = n[1] let t2 = fmt"{t.repr[1.. r: swap(l, r) let d = r - l let eps = Real$.eps if d < eps: return true if l <= Real(0) and Real(0) <= r: return false return d < eps * min(abs(l), abs(r)) template initPrec*(Real:typedesc) = Real$.pi = PI.Real Real$.inf = Inf.Real when Real is float or Real is float64: Real$.eps = 1e-9.Real elif Real is float32: Real$.eps = 1e-9.Real # float comp # TODO: relative error proc `=~`*(a,b:Real):bool = abs(a - b) < Real$.eps proc `!=~`*(a,b:Real):bool = abs(a - b) > Real$.eps proc `<~`*(a,b:Real):bool = a + Real$.eps < b proc `>~`*(a,b:Real):bool = a > b + Real$.eps proc `<=~`*(a,b:Real):bool = a < b + Real$.eps proc `>=~`*(a,b:Real):bool = a + Real$.eps > b # for OMC proc estimateRational*[Real](x:Real, n:int) = var m = Real$.inf var q = 1 while q <= n: let p = round(x * q.Real) let d = abs(p / q.Real - x) if d < m: m = d echo "found: ", p, "/", q, " ", "error: ", d q.inc return float.initPrec() # float64.initPrec() float32.initPrec() discard #[ import atcoder/extra/other/zip ]# when not declared ATCODER_ZIP_HPP: const ATCODER_ZIP_HPP* = 1 import macros macro zip*(v:varargs[untyped]):untyped = result = newStmtList() var par = newPar() for i,a in v: var ts = newNimNode(nnkTypeSection) par.add(ident("T" & $i)) ts.add(newNimNode(nnkTypeDef).add( ident("T" & $i), newEmptyNode(), newDotExpr(newNimNode(nnkBracketExpr).add(a, newIntLitNode(0)), ident("type")) )) result.add ts var varSection = newNimNode(nnkVarSection) varSection.add newIdentDefs(ident("a"), newEmptyNode(), newCall( newNimNode(nnkBracketExpr).add( ident("newSeq"), par ), ident("n") )) result.add newNimNode(nnkLetSection).add(newIdentDefs(ident("n"), newEmptyNode(), newDotExpr(v[0] , ident("len")) )) result.add(varSection) var forStmt = newNimNode(nnkForStmt).add(ident("i")).add( newNimNode(nnkInfix).add(ident("..<")).add(newIntLitNode(0), ident("n")) ) var fs = newStmtList() for j,a in v: fs.add newAssignment( newNimNode(nnkBracketExpr).add( newNimNode(nnkBracketExpr).add( ident("a"), ident("i") ), newIntLitNode(j)), newNimNode(nnkBracketExpr).add( a, ident("i") ) ) forStmt.add fs result.add(forStmt) result.add(ident("a")) result = newBlockStmt(newEmptyNode(), result) macro unzip*(n:int, p:tuple):untyped = result = newStmtList() result.add(newNimNode(nnkLetSection).add(newIdentDefs(ident("n"), newEmptyNode(), n))) for i,a in p: var a = newPar(a) var t = newCall( newNimNode(nnkBracketExpr).add( ident("newSeq"), newDotExpr(a, ident("type")) ), ident("n") ) var varSection = newNimNode(nnkVarSection).add( newIdentDefs(ident("a" & $i), newEmptyNode(), t), ) result.add(varSection) var forStmt = newNimNode(nnkForStmt).add(ident("i")) var rangeDef = newNimNode(nnkInfix).add(ident("..<")).add(newIntLitNode(0), ident("n")) forStmt.add(rangeDef) var fs = newStmtList() for i,a in p: fs.add newAssignment( newNimNode(nnkBracketExpr).add( ident("a" & $i), ident("i")), a ) forStmt.add fs result.add(forStmt) var par = newPar() for i, a in p: par.add(ident("a" & $i)) result.add(par) result = newBlockStmt(newEmptyNode(), result) discard #[ import atcoder/extra/other/solve_proc ]# when not declared ATCODER_SOLVEPROC_HPP: const ATCODER_SOLVEPROC_HPP* = 1 import std/macros import std/strformat import std/algorithm import std/sequtils import std/streams import std/strutils import math proc compare_answer_string*(s, t:string, error:float = NaN):bool = if error.classify == fcNaN: return s == t else: var s = s.split("\n") t = t.split("\n") if s.len != t.len: return false for i in 0 ..< s.len: var s = s[i].split() var t = t[i].split() if s.len != t.len: return false for j in 0 ..< s.len: if s[j].len == 0: if t[j].len != 0: return false elif t[j].len == 0: return false else: var fs = s[j].parseFloat var ft = t[j].parseFloat if abs(fs - ft) > error and abs(fs - ft) > min(abs(ft), abs(fs)) * error: return false return true doAssert false proc mainBodyHeader():NimNode = # let macro_def = "(for s in {x.repr}: (result &= $s;(when output_stdout: stdout.write $s)));(result &= \"\\n\";when output_stdout: stdout.write \"\\n\")" result = newStmtList() result.add quote("@@") do: mixin echo result = "" var resultPointer = result.addr proc echo(x:varargs[string, `$`]) = for s in x: resultPointer[] &= $s when output_stdout: stdout.write $s resultPointer[] &= "\n" when output_stdout: stdout.write "\n" macro solveProc*(head, body:untyped):untyped = var prev_type:NimNode var params:seq[NimNode] for i in countdown(head.len - 1, 1): var identDefs = newNimNode(nnkIdentDefs) if head[i].kind == nnkExprColonExpr: identDefs.add(head[i][0]) prev_type = head[i][1] elif head[i].kind == nnkIdent: identDefs.add(head[i]) identDefs.add(prev_type) identDefs.add(newEmptyNode()) params.add(identDefs) params.add(ident"auto") params.reverse() var callparams:seq[NimNode] for i in 1.. b[i]: return false if a.len < b.len: return true else: return false proc ceilDiv*[T:SomeInteger](a, b:T):T = assert b != 0 if b < 0: return ceilDiv(-a, -b) result = a.floorDiv(b) if a mod b != 0: result.inc template `/^`*[T:SomeInteger](a, b:T):T = ceilDiv(a, b) discard block: var a, n = nextInt() x = 1 for i in 0 ..< n: x *= a if x in 10^7 .. 10^18: echo x echo 0 break echo 10^18 echo x