//spnauti-rust
#[allow(unused_macros)]
macro_rules! a {
    ($c: tt, $x: expr, $y: expr) => {{
        let b = $y; let a = &mut $x;
        if b $c *a { *a = b; true } else { false }
    }};
}
use std::io::*;
use std::str::*;
use std::fmt::Debug;
struct WordReader<'a> { it : SplitAsciiWhitespace<'a>, }
#[allow(dead_code)]
impl<'a> WordReader<'a> {
    fn new<T: Read>(b: &mut String, mut r: T) -> WordReader {
        b.clear();
        r.read_to_string(b).unwrap();
        WordReader { it: b.split_ascii_whitespace() }
    }
    fn from_stdin(b: &mut String) -> WordReader {
        WordReader::new(b, stdin())
    }
    fn sl(&mut self) ->  &str { self.it.next().unwrap() }
    fn bs(&mut self) -> &[u8] { self.sl().as_bytes()    }
    fn s(&mut self) -> String { String::from(self.sl()) }
    fn i(&mut self) ->    i32 { self.p()                }
    fn p<T: FromStr>(&mut self) -> T where T::Err: Debug {
        self.sl().parse::<T>().unwrap()
    }
    fn vp<T: FromStr>(&mut self, n: usize) -> Vec<T> where T::Err: Debug {
        (0..n).map(|_| self.p()).collect()
    }
}

fn main() {
    let mut bin = String::new();
    let mut input = WordReader::from_stdin(&mut bin);

    let sol = input.bs().iter().fold((b'a',0), |(c,res),&a| {
        let d = (a as i32) - (c as i32);
        let t = [-26, 0, 26].iter()
            .map(|x| (d + x).abs()).min().unwrap();
        (a, res + t)
    }).1;
    println!("{}", sol);
}


#[allow(unused_imports)]
use std::cmp::{max,min};
#[allow(unused_imports)]
use std::collections::{HashMap,HashSet,VecDeque};

#[allow(unused_macros)]
macro_rules! readln {
    () => {{
        use std::io;

        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim().to_string()
    }};
    ( $t:ty ) => {{
        let input = readln!();
        input.parse::<$t>().unwrap()
    }};
    ( $( $t:ty ),+ ) => {{
        let input = readln!();
        let mut input = input.split_whitespace();
        (
            $(
                input.next().unwrap().parse::<$t>().unwrap(),
            )+
        )
    }}
}

#[allow(unused_macros)]
macro_rules! readvec {
    ( $t:ty ) => {{
        let input = readln!();
        let mut input = input.split_whitespace();
        let mut result = Vec::new();
        for elem in input {
            result.push(elem.parse::<$t>().unwrap());
        }
        result
    }}
}

fn main() {
    let s = String::from("a") + readln!().as_ref();
    let ans = s.chars().zip(s.chars().skip(1)).map(|(x,y)|{ min((x as u8 + 26 - y as u8) % 26, (y as u8 + 26 - x as u8) % 26) as i32 } ).sum::<i32>();
    println!("{}",ans);
}


fn hash(a: &[usize], cnt: &[usize]) -> usize {
    let mut hash = 0;
    for i in 0..10 {
        hash = (cnt[i] + 1) * hash + a[i];
    }
    hash
}

fn decode(mut hash: usize, cnt: &[usize]) -> Vec<usize> {
    let mut d = vec![];
    for i in (0..10).rev() {
        d.push(hash % (cnt[i] + 1));
        hash /= cnt[i] + 1;
    }
    d.reverse();
    d
}

fn run() {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    let mut it = s.trim().split_whitespace();
    let mut n: u64 = it.next().unwrap().parse().unwrap();
    let m: usize = it.next().unwrap().parse().unwrap();
    let mut cnt = vec![0; 10];
    while n > 0 {
        let k = (n % 10) as usize;
        cnt[k] += 1;
        n /= 10;
    }
    let mut step = vec![1; 10];
    for i in (0..9).rev() {
        step[i] = step[i + 1] * (cnt[i + 1] + 1);
    }
    let hash_sup = hash(&cnt, &cnt) + 1;
    let mut dp = vec![0u64; hash_sup * m];
    let mut used = vec![false; hash_sup * m];
    dp[(hash_sup - 1) * m + 0] = 1;
    used[(hash_sup - 1) * m + 0] = true;
    let mut q = std::collections::VecDeque::new();
    q.push_back((hash_sup - 1) * m + 0);
    while let Some(v) = q.pop_front() {
        let rem = v % m;
        let h = v / m;
        let a = decode(h, &cnt);
        for d in 0..10 {
            if a[d] > 0 && !(d == 0 && a == cnt) {
                let r = (10 * rem + d) % m;
                let u = (h - step[d]) * m + r;
                dp[u] += dp[v];
                if !used[u] {
                    used[u] = true;
                    q.push_back(u);
                }
            }
        }
    }
    let ans = dp[0 * m + 0];
    println!("{}", ans);
}

fn main() {
    run();
}


fn run() {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    let mut it = s.trim().split_whitespace();
    let mut n: u64 = it.next().unwrap().parse().unwrap();
    let m: usize = it.next().unwrap().parse().unwrap();
    let p = 10;
    let mut cnt = vec![0; p];
    while n > 0 {
        let k = (n % p as u64) as usize;
        cnt[k] += 1;
        n /= p as u64;
    }
    let mut step = vec![1; p + 1];
    for i in (0..p).rev() {
        step[i] = step[i + 1] * (cnt[i] + 1);
    }
    let len = step[0];
    let mut dp = vec![vec![0u64; len]; m];
    dp[0][len - 1] = 1;
    let mut q = std::collections::VecDeque::new();
    q.push_back((0, len - 1));
    while let Some((rem, v)) = q.pop_front() {
        for d in 0..p {
            let a = v % step[d] / step[d + 1];
            if a > 0 && !(d == 0 && v == len - 1) {
                let u = v - step[d + 1];
                let r = (10 * rem + d) % m;
                if dp[r][u] == 0 {
                    q.push_back((r, u));
                }
                dp[r][u] += dp[rem][v];
            }
        }
    }
    let ans = dp[0][0];
    println!("{}", ans);
}

fn main() {
    run();
}


//spnauti-rusT {{{
use std::io::*; use std::str::{self,*}; use std::fmt::Debug;
#[allow(unused_imports)] use std::cmp::Ordering::{self,*};
#[allow(unused_imports)] use std::ops::{self,*};
#[allow(unused_imports)] use std::iter::{self,*};
#[allow(unused_imports)] use std::collections::*;
#[allow(unused_imports)] use std::cell::*;
#[allow(unused_macros)] macro_rules! m {
	($c:tt,$x:expr,$y:expr) => {{
		let b=$y; let a=&mut$x; if b$c*a {*a=b; true} else {false}
	}};
}
#[allow(unused_macros)] macro_rules! l {
	($($v:ident),+ =$e:expr) => {$(let$v=$e;)+};
	($($v:ident),+:$t:ty=$e:expr) => {$(let$v:$t=$e;)+};
	(mut $($v:ident),+ =$e:expr) => {$(let mut$v=$e;)+};
	(mut $($v:ident),+:$t:ty=$e:expr) => {$(let mut$v:$t=$e;)+};
}
#[allow(unused_macros)] macro_rules! rep { {[$c:expr]$($s:tt)+} => {for _ in 0..$c {$($s)+}} }
#[allow(dead_code)] fn reader() -> WordReaderC { WordReaderC::new() }
#[allow(dead_code)] fn writer() -> BufWriter<Stdout> { BufWriter::new(stdout()) }
struct WordReaderC {buf: Vec<u8>, pos: usize, q: std::io::StdinLock<'static>}//'
#[allow(dead_code)] impl WordReaderC {
	fn new() -> Self {
		let r = unsafe {&*Box::into_raw(Box::new(stdin()))};
		Self { q: r.lock(), buf: Vec::new(), pos: 0 }
	}
	fn next_line(&mut self) -> bool {
		self.buf.clear(); self.pos = 0;
		self.q.read_until(b'\n', &mut self.buf).unwrap_or(0) > 0
	}
	fn is_ws(c: u8) -> bool {
		c == b' ' || c == b'\r' || c == b'\n' || c == b'\t'
	}
	fn byte(&mut self) -> Option<u8> {
		if self.pos == self.buf.len() { if !self.next_line() { return None; } }
		self.pos += 1; Some(self.buf[self.pos - 1])
	}
	fn vb(&mut self) -> Vec<u8> {
		let mut s = Vec::with_capacity(8);
		let mut f = false;
		loop {
			if let Some(c) = self.byte() {
				if !Self::is_ws(c) {
					s.push(c);
					f = true;
				} else if f { break; }
			} else { break; }
		}
		s
	}
	fn s(&mut self) -> String { String::from_utf8(self.vb()).expect("invalid utf8") }
	fn i(&mut self) ->    i32 { self.p() }
	fn l(&mut self) ->    i64 { self.p() }
	fn u(&mut self) ->  usize { self.p() }
	fn f(&mut self) ->    f64 { self.p() }
	fn vi(&mut self, n: usize) -> Vec<i32> { self.vp(n) }
	fn vl(&mut self, n: usize) -> Vec<i64> { self.vp(n) }
	fn vu(&mut self, n: usize) -> Vec<usize> { self.vp(n) }
	fn ii(&mut self, n: usize) -> impl Iterator<Item=i32> { self.ip(n).into_iter() }
	fn iu(&mut self, n: usize) -> impl Iterator<Item=usize> { self.ip(n).into_iter() }
	fn p<T: FromStr>(&mut self) -> T where T::Err: Debug {
		let w = self.vb(); str::from_utf8(w.as_ref()).unwrap().parse::<T>().unwrap()
	}
	fn vp<T: FromStr>(&mut self, n: usize) -> Vec<T> where T::Err: Debug {
		(0..n).map(|_|self.p()).collect()
	}
	fn ip<T: FromStr>(&mut self, n: usize) -> impl Iterator<Item=T> where T::Err: Debug {
		self.vp(n).into_iter()
	}
}
//------------------- End rusT }}}

fn main() {
	let mut rin = reader();
	let mut rout = writer();

	let mut c0 = vec![1; 10];
	for x in rin.vb() {
		c0[(x - b'0') as usize] += 1;
	}
	let m = rin.u();
	let mut ns = 1;
	for &c in c0.iter() {
		ns *= c;
	}
	let encode = |a: &[usize]| -> usize {
		let mut res = 0;
		for i in 0..10 {
			res = res * c0[i] + a[i];
		}
		res
	};
	let decode = |a: &mut [usize], mut x: usize| {
		for i in (0..10).rev() {
			a[i] = x % c0[i];
			x /= c0[i];
		}
	};
	let mut dp = vec![vec![0; m]; ns];
	dp[0][0] = 1_i64;
	for s in 0..ns {
		let mut a = vec![0; 10];
		decode(&mut a, s);
		let st = if s == 0 {1} else {0};
		for r in 0..m {
			let v = dp[s][r];
			if v == 0 { continue; }
			for i in st..10 {
				if a[i]+1 < c0[i] {
					a[i] += 1;
					let ss = encode(&a);
					dp[ss][(r * 10 + i) % m] += v;
					a[i] -= 1;
				}
			}
		}
	}
	let sol = dp[ns-1][0];
	writeln!(rout, "{}", sol).ok();
}


fn hash(a: &[u64], cnt: &[u64]) -> u64 {
    let mut hash = 0;
    for i in 0..10 {
        hash = (cnt[i] + 1) * hash + a[i];
    }
    hash
}

fn decode(mut hash: u64, cnt: &[u64]) -> Vec<u64> {
    let mut d = vec![];
    for i in (0..10).rev() {
        d.push(hash % (cnt[i] + 1));
        hash /= cnt[i] + 1;
    }
    d.reverse();
    d
}

fn run() {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    let mut it = s.trim().split_whitespace();
    let mut n: u64 = it.next().unwrap().parse().unwrap();
    let m: usize = it.next().unwrap().parse().unwrap();
    let mut cnt = vec![0; 10];
    let mut len = 0;
    while n > 0 {
        let k = (n % 10) as usize;
        cnt[k] += 1;
        len += 1;
        n /= 10;
    }
    let mut now = std::collections::BTreeMap::new();
    now.insert((hash(&cnt, &cnt), 0), 1u64);
    for p in 0..len {
        let mut next = std::collections::BTreeMap::new();
        for (k, v) in now.iter() {
            let (h, rem) = *k;
            let a = decode(h, &cnt);
            for d in 0..10 {
                if a[d] > 0 && !(p == 0 && d == 0) {
                    let mut b = a.clone();
                    b[d] -= 1;
                    let r = (10 * rem + d) % m;
                    *next.entry((hash(&b, &cnt), r)).or_insert(0u64) += *v;
                }
            }
        }
        now = next;
    }
    let mut ans = 0;
    for (k, v) in now.iter() {
        if k.1 == 0 {
            ans += *v;
        }
    }
    println!("{}", ans);
}

fn main() {
    run();
}


struct Scan {
    buffer: std::collections::VecDeque<String>,
}

impl Scan {
    fn new() -> Scan {
        Scan {
            buffer: std::collections::VecDeque::new(),
        }
    }

    fn next<T: std::str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop_front() {
                break token.parse::<T>().ok().unwrap();
            }
            let mut line = String::new();
            std::io::stdin().read_line(&mut line).expect("Fail to read");
            self.buffer = line.split_whitespace().map(String::from).collect();
        }
    }
}

fn _main() {
    let mut scan = Scan::new();
    let _n: usize = scan.next();
    let input: Vec<char> = scan.next::<String>().chars().collect();
    let mut cnt = 0usize;
    let mut res = 0usize;
    if input[0] == 'x' {
        cnt += 1
    };
    for i in 1..input.len() {
        if input[i] == 'x' {
            if input[i - 1] == 'x' {
                if cnt + 1 >= 3 {
                    res += 1;
                } else {
                    cnt += 1;
                }
            } else {
                cnt = 1;
            }
        } else {
            cnt = 0;
        }
    }
    println!("{}", res);
}

fn main() {
    std::thread::Builder::new()
        .stack_size(1 << 23)
        .spawn(_main)
        .unwrap()
        .join()
        .unwrap();
}


use std::cmp;
use std::io;
use std::io::Read;

fn main() {
    let mut mut_line = String::new();
    io::stdin().read_line(&mut mut_line).unwrap();
    io::stdin().read_line(&mut mut_line).unwrap();

    let mut remove_count = 0;
    let mut con_count = 0;

    for i in mut_line.into_bytes() {
        if i == 0x78 {
            con_count += 1;
        } else {
            remove_count += cmp::max(0, con_count - 2);
            con_count = 0;
        }
    }
    // We don't need the final one because the loop goes on for
    // len(input string) + 1 because of the trailing new line.
    println!("{}", remove_count);
}


// Basics

#![allow(unused_imports)]
#![allow(dead_code)]

//extern crate rand;

use std::io::prelude::*;
use std::mem;
use std::io;
use std::io::BufRead;
use std::io::BufReader;
use std::string;
use std::cmp::*;
use std::collections::*;
use std::vec::Vec;
use std::collections::LinkedList;
use std::num;
use std::ops;
use std::ops::Index;
use std::fmt::Debug;
use std::str::FromStr;
use std::ops::Shr;

struct Cin {
    data: LinkedList<String>,
}

impl Cin {
    fn new() -> Self {
        Cin { data: LinkedList::new() }
    }
    fn read_line(&self) -> String {
        let mut s: String = String::new();
        io::stdin().read_line(&mut s).expect("err");
        s
    }
    fn read_str(&mut self) -> String {
        if self.data.len() == 0 {
            let s = self.read_line();
//            let split = s.split("\\s+");
            let split = s.split_whitespace();
            for el in split {
                self.data.push_back(String::from(el));
            }
        }
        self.data.pop_front().expect("empty")
    }
    fn read_int(&mut self) -> i64 {
        self.read_str().parse().expect("err parse")
    }
    fn read_vec(&mut self, ref size: i64) -> Vec<i64> {
        let mut v: Vec<i64> = Vec::new();
        for _i in 0..*size {
            v.push(self.read_int());
        }
        v
    }
}

fn main() {
    let mut cin = Cin::new();
    let n = cin.read_int() as usize;
    let line = cin.read_str();
    let mut sum = 0;
    for i in 0..n - 2 {
        sum += if line.index(i..i + 3) == "xxx" { 1 } else { 0 };
    }
    println!("{}", sum);
}


use std::io::Read;

fn main() {
  let mut text = String::new();
  std::io::stdin().read_to_string(&mut text).unwrap();

  let res: usize = text
              .split_whitespace()
              .skip(1)
              .map(|e| e.parse::<String>().unwrap())
              .next()
              .unwrap()
              .split(|c| c != 'x')
              .filter_map(|s| if s.len() > 2 { Some(s.len() - 2 ) } else { None })
              .sum();
  println!("{}", res);
}


//spnauti-rust
use std::io::*;
use std::str::*;
use std::fmt::Debug;
#[allow(unused_imports)] use std::cmp::Ordering::*;
#[allow(unused_imports)] use std::collections::*;

#[allow(unused_macros)]
macro_rules! a {
    ($c: tt, $x: expr, $y: expr) => {{
        let b = $y; let a = &mut $x;
        if b $c *a { *a = b; true } else { false }
    }};
}
struct WordReader<'a> { it : SplitAsciiWhitespace<'a>, }
#[allow(dead_code)]
impl<'a> WordReader<'a> {
    fn new<T: Read>(b: &mut String, mut r: T) -> WordReader {
        b.clear();
        r.read_to_string(b).unwrap();
        WordReader { it: b.split_ascii_whitespace() }
    }
    fn from_stdin(b: &mut String) -> WordReader {
        WordReader::new(b, stdin())
    }
    fn sl(&mut self) ->  &str { self.it.next().unwrap() }
    fn bs(&mut self) -> &[u8] { self.sl().as_bytes()    }
    fn s(&mut self) -> String { String::from(self.sl()) }
    fn i(&mut self) ->    i32 { self.p()                }
    fn u(&mut self) ->  usize { self.p()                }
    fn vi(&mut self, n: usize) -> Vec<i32> {
        self.vp::<i32>(n)
    }
    fn p<T: FromStr>(&mut self) -> T where T::Err: Debug {
        self.sl().parse::<T>().unwrap()
    }
    fn vp<T: FromStr>(&mut self, n: usize) -> Vec<T> where T::Err: Debug {
        (0..n).map(|_| self.p()).collect()
    }
}

#[allow(dead_code)]
fn build_counting_hashmap<K: Eq + std::hash::Hash, T>(i: T) -> HashMap<K,usize>
    where T: Iterator<Item = K> {
    let mut m = HashMap::new();
    for k in i {
        let n = 1 + if let Some(&n) = m.get(&k) { n } else { 0 };
        m.insert(k, n);
    }
    m
}

fn main() {
    let mut bin = String::new();
    let mut input = WordReader::from_stdin(&mut bin);

    let _n = input.u();
    let sol = input.bs().split(|&c| c != b'x').map(|z| z.len().max(2) - 2).sum::<usize>();
    println!("{}", sol);
}


#![allow(unused_imports)]
#![allow(unused_macros)]
#![allow(dead_code)]
#![allow(unused_labels)]

use std::char::*;
use std::cmp::*;
use std::collections::*;
use std::io::*;
use std::str::FromStr;

macro_rules! debug {($($a:expr),*) => {eprintln!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);}}
macro_rules! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut iter = $ s . split_whitespace ( ) ; let mut next = || { iter . next ( ) . unwrap ( ) } ; input_inner ! { next , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { let stdin = std :: io :: stdin ( ) ; let mut bytes = std :: io :: Read :: bytes ( std :: io :: BufReader :: new ( stdin . lock ( ) ) ) ; let mut next = move || -> String { bytes . by_ref ( ) . map ( | r | r . unwrap ( ) as char ) . skip_while ( | c | c . is_whitespace ( ) ) . take_while ( | c |! c . is_whitespace ( ) ) . collect ( ) } ; input_inner ! { next , $ ( $ r ) * } } ; }
macro_rules! input_inner { ( $ next : expr ) => { } ; ( $ next : expr , ) => { } ; ( $ next : expr , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ next , $ t ) ; input_inner ! { $ next $ ( $ r ) * } } ; }
macro_rules! read_value { ( $ next : expr , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ next , $ t ) ) ,* ) } ; ( $ next : expr , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ next , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ next : expr , chars ) => { read_value ! ( $ next , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ next : expr , usize1 ) => { read_value ! ( $ next , usize ) - 1 } ; ( $ next : expr , $ t : ty ) => { $ next ( ) . parse ::<$ t > ( ) . expect ( "Parse error" ) } ; }

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

use std::f64;

fn min<T: PartialOrd>(a:T, b:T) -> T {
    if a < b { a }
    else { b }
}

fn max<T: PartialOrd>(a:T, b:T) -> T {
    if a < b { b }
    else { a }
}

const MAX:usize = 30;
const INF:i64 = std::i64::MAX;
const MOD:i64 = 1e9 as i64 + 7;

struct Graph {
    e: Vec<Vec<usize>>,
    v: Vec<usize>,
    u: Vec<usize>,
    f: Vec<bool>,
    c: i64,
    vc: Vec<i64>,
}

impl Graph {
    fn new(n:usize) -> Self {
        Graph {
            e: vec![vec![];n],
            v: vec![],
            u: vec![n;n],
            f: vec![false;n],
            c: 0,
            vc: vec![0;n],
        }
    }

    fn dfs(&mut self, crt: usize) {
        if self.f[crt] { return; }
        self.c += 1;
        self.f[crt] = true;
        self.v.push(crt);
        self.vc[crt] = self.c;
        self.u[crt] = self.v.len()-1;
        for i in 0..self.e[crt].len() {
            self.dfs(self.e[crt][i]);
        }
        //debug!(crt, self.c, self.vc[crt]);
        self.vc[crt] = self.c - self.vc[crt];
    }
}

fn main() {
    //let t:usize = read();

    //'outer: for _ in 0..t {
        let n:usize = read();
        let s:Vec<char> = read::<String>().chars().collect();

        let mut cnt = 0;
        let mut ans = 0;
        for i in 0..n {
            if s[i]=='x' {
                cnt += 1;
            } else {
                if cnt >= 3 {
                    ans += cnt-2;
                }
                cnt = 0;
            }
        }
        println!("{}", ans+max(0,cnt-2));
    //}
}

/*

*/


fn main() {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).expect("INPUT::read line failed");

    let amount = input.trim().parse::<usize>().expect("AMOUNT::parse to usize failed");
    input.clear();

    std::io::stdin().read_line(&mut input).expect("INPUT::read line failed");
    let mut chars = input.trim().chars();

    let mut max_length = i32::default();
    let mut vec = vec![];
    loop {
        match chars.next() {
            Some(value) => {
                if value == 'x' {
                    max_length += 1;
                } else {
                    vec.push(max_length);
                    max_length = 0;
                }

            },

            None => {
                if max_length != 0 {
                    vec.push(max_length);
                }
                break;
            }
        }
    }

    let mut modify_times = i32::default();
    for item in vec.iter() {
        if *item >= 3 {
            modify_times += item - 2;
        }
    }

    println!("{}", modify_times);

}


fn raw_input() -> String {
    let mut buf = String::new();
    std::io::stdin().read_line(&mut buf).unwrap();
    buf.trim().to_string()
}

fn main() {
    {
        let mut buf = String::new();
        std::io::stdin().read_line(&mut buf).unwrap();
    }

    let input = raw_input();
    let (mut x_count, mut to_remove) = (0, 0);
    for c in input.chars() {
        if c == 'x' {
            if x_count >= 2 {
                to_remove += 1;
            }
            x_count += 1;
        } else {
            x_count = 0;
        }
    }

    print!("{}", to_remove);
}


// https://codeforces.com/contest/1242/problem/A
//
#![allow(unused_imports)]
use std::io::*;
use std::io::Write;
use std::fmt::*;
use std::str::*;
use std::cmp::*;
use std::collections::*;

#[allow(unused_macros)]
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

#[allow(unused_macros)]
macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };

    ($iter:expr, mut $var:ident : $t:tt $($r:tt)*) => {
        let mut $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

#[allow(unused_macros)]
macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, [ next / $t:tt ]) => {
        {
            let len = read_value!($iter, usize);
            (0..len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
        }
    };

    ($iter:expr, switch) => {
        {
            let ty = read_value!($iter, i32);
            if ty == 1 {
                vec![ty, read_value!($iter, i32), read_value!($iter, i32)]
            } else if ty == 2 {
                vec![ty, read_value!($iter, i32)]
            } else {
                vec![ty, read_value!($iter, i32)]
            }
        }
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}

#[allow(unused_macros)]
macro_rules! dvec {
    ($t:expr ; $len:expr) => {
        vec![$t; $len]
    };

    ($t:expr ; $len:expr, $($rest:expr),*) => {
        vec![dvec!($t; $($rest),*); $len]
    };
}

#[allow(unused_macros)]
macro_rules! ifv {
    ($t:expr, $a:expr, $b: expr) => {
        if $t { $a } else { $b }
    }
}

#[allow(unused_macros)]
macro_rules! fill {
    ($t:expr, $v:expr) => {
        for i in 0..$t.len() {
            $t[i] = $v;
        }
    };
}

#[allow(unused_macros)]
macro_rules! join {
    ($t:expr, $glue:expr) => {
        $t.into_iter().map(|w| w.to_string()).collect::<Vec<_>>().join($glue)
    };
}

#[allow(unused_macros)]
macro_rules! debug {
    ($($a:expr),*) => {
        println!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);
    }
}

fn gcd(a: i64, b: i64) -> i64 {
    if b == 0 {
        a
    } else {
        gcd(b, a%b)
    }
}

fn main() {
    input! {
        n: i64
    };

    let mut ans = n;
    for i in 1..n+1 {
        if i * i > n {
            break;
        }
        if n % i == 0 {
            if i >= 2 {
                ans = gcd(ans, i);
            }
            if n/i >= 2 {
                ans = gcd(ans, n/i);
            }
        }
    }
    println!("{}", ans);
}


pub trait Readable {
    type Output;
    fn words_count() -> usize;
    fn read_words(words: &[&str]) -> Result<Self::Output, String>;
}
#[macro_export]
macro_rules! readable {
    ( $ t : ty , $ words_count : expr , |$ words : ident | $ read_words : expr ) => {
        impl Readable for $t {
            type Output = $t;
            fn words_count() -> usize {
                $words_count
            }
            fn read_words($words: &[&str]) -> Result<$t, String> {
                Ok($read_words)
            }
        }
    };
}
readable!((), 1, |_ss| ());
readable!(String, 1, |ss| ss[0].to_string());
impl Readable for char {
    type Output = char;
    fn words_count() -> usize {
        1
    }
    fn read_words(words: &[&str]) -> Result<char, String> {
        let chars: Vec<char> = words[0].chars().collect();
        if chars.len() == 1 {
            Ok(chars[0])
        } else {
            Err(format!("cannot parse `{}` as a char", words[0]))
        }
    }
}
pub struct Chars();
impl Readable for Chars {
    type Output = Vec<char>;
    fn words_count() -> usize {
        1
    }
    fn read_words(words: &[&str]) -> Result<Vec<char>, String> {
        Ok(words[0].chars().collect())
    }
}
macro_rules ! impl_readable_for_ints { ( $ ( $ t : ty ) * ) => { $ ( impl Readable for $ t { type Output = Self ; fn words_count ( ) -> usize { 1 } fn read_words ( words : & [ & str ] ) -> Result <$ t , String > { use std :: str :: FromStr ; <$ t >:: from_str ( words [ 0 ] ) . map_err ( | _ | { format ! ( "cannot parse `{}` as {}" , words [ 0 ] , stringify ! ( $ t ) ) } ) } } ) * } ; }
impl_readable_for_ints ! ( i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 ) ;
macro_rules ! define_one_origin_int_types { ( $ new_t : ident $ int_t : ty ) => { # [ doc = " Converts 1-origin integer into 0-origin when read from stdin." ] # [ doc = "" ] # [ doc = " # Example" ] # [ doc = "" ] # [ doc = " ```no_run" ] # [ doc = " # #[macro_use] extern crate atcoder_snippets;" ] # [ doc = " # use atcoder_snippets::read::*;" ] # [ doc = " // Stdin: \"1\"" ] # [ doc = " read!(a = usize_);" ] # [ doc = " assert_eq!(a, 0);" ] # [ doc = " ```" ] # [ allow ( non_camel_case_types ) ] pub struct $ new_t ; impl Readable for $ new_t { type Output = $ int_t ; fn words_count ( ) -> usize { 1 } fn read_words ( words : & [ & str ] ) -> Result < Self :: Output , String > { <$ int_t >:: read_words ( words ) . map ( | n | n - 1 ) } } } ; ( $ new_t : ident $ int_t : ty ; $ ( $ inner_new_t : ident $ inner_int_t : ty ) ;* ) => { define_one_origin_int_types ! ( $ new_t $ int_t ) ; define_one_origin_int_types ! ( $ ( $ inner_new_t $ inner_int_t ) ;* ) ; } ; }
define_one_origin_int_types ! ( u8_ u8 ; u16_ u16 ; u32_ u32 ; u64_ u64 ; usize_ usize ) ;
macro_rules ! impl_readable_for_tuples { ( $ t : ident $ var : ident ) => ( ) ; ( $ t : ident $ var : ident ; $ ( $ inner_t : ident $ inner_var : ident ) ;* ) => { impl_readable_for_tuples ! ( $ ( $ inner_t $ inner_var ) ;* ) ; impl <$ t : Readable , $ ( $ inner_t : Readable ) ,*> Readable for ( $ t , $ ( $ inner_t ) ,* ) { type Output = ( <$ t >:: Output , $ ( <$ inner_t >:: Output ) ,* ) ; fn words_count ( ) -> usize { let mut n = <$ t >:: words_count ( ) ; $ ( n += <$ inner_t >:: words_count ( ) ; ) * n } # [ allow ( unused_assignments ) ] fn read_words ( words : & [ & str ] ) -> Result < Self :: Output , String > { let mut start = 0 ; let $ var = <$ t >:: read_words ( & words [ start .. start +<$ t >:: words_count ( ) ] ) ?; start += <$ t >:: words_count ( ) ; $ ( let $ inner_var = <$ inner_t >:: read_words ( & words [ start .. start +<$ inner_t >:: words_count ( ) ] ) ?; start += <$ inner_t >:: words_count ( ) ; ) * Ok ( ( $ var , $ ( $ inner_var ) ,* ) ) } } } ; }
impl_readable_for_tuples ! ( T8 x8 ; T7 x7 ; T6 x6 ; T5 x5 ; T4 x4 ; T3 x3 ; T2 x2 ; T1 x1 ) ;
pub trait ReadableFromLine {
    type Output;
    fn read_line(line: &str) -> Result<Self::Output, String>;
}
fn split_into_words(line: &str) -> Vec<&str> {
    #[allow(deprecated)]
    line.trim_right_matches('\n').split_whitespace().collect()
}
impl<T: Readable> ReadableFromLine for T {
    type Output = T::Output;
    fn read_line(line: &str) -> Result<T::Output, String> {
        let words = split_into_words(line);
        if words.len() != T::words_count() {
            return Err(format!(
                "line `{}` has {} words, expected {}",
                line,
                words.len(),
                T::words_count()
            ));
        }
        T::read_words(&words)
    }
}
macro_rules ! impl_readable_from_line_for_tuples_with_from_iterator { ( $ u : ident : $ ( + $ bound : path ) * => $ seq_in : ty , $ seq_out : ty ; $ t : ident $ var : ident ) => { impl <$ u : Readable > ReadableFromLine for $ seq_in where <$ u as Readable >:: Output : Sized $ ( + $ bound ) * { type Output = $ seq_out ; fn read_line ( line : & str ) -> Result <$ seq_out , String > { let n = $ u :: words_count ( ) ; let words = split_into_words ( line ) ; if words . len ( ) % n != 0 { return Err ( format ! ( "line `{}` has {} words, expected multiple of {}" , line , words . len ( ) , n ) ) ; } let mut result = Vec :: new ( ) ; for chunk in words . chunks ( n ) { match $ u :: read_words ( chunk ) { Ok ( v ) => result . push ( v ) , Err ( msg ) => { let flagment_msg = if n == 1 { format ! ( "word {}" , result . len ( ) ) } else { let l = result . len ( ) ; format ! ( "words {}-{}" , n * l + 1 , ( n + 1 ) * l ) } ; return Err ( format ! ( "{} of line `{}`: {}" , flagment_msg , line , msg ) ) ; } } } Ok ( result . into_iter ( ) . collect ( ) ) } } impl < T : Readable , $ u : Readable > ReadableFromLine for ( T , $ seq_in ) where <$ u as Readable >:: Output : Sized $ ( + $ bound ) * { type Output = ( T :: Output , $ seq_out ) ; fn read_line ( line : & str ) -> Result < Self :: Output , String > { let n = T :: words_count ( ) ; # [ allow ( deprecated ) ] let trimmed = line . trim_right_matches ( '\n' ) ; let words_and_rest : Vec <& str > = trimmed . splitn ( n + 1 , ' ' ) . collect ( ) ; if words_and_rest . len ( ) < n { return Err ( format ! ( "line `{}` has {} words, expected at least {}" , line , words_and_rest . len ( ) , n ) ) ; } let words = & words_and_rest [ .. n ] ; let empty_str = "" ; let rest = words_and_rest . get ( n ) . unwrap_or ( & empty_str ) ; Ok ( ( T :: read_words ( words ) ?, <$ seq_in >:: read_line ( rest ) ? ) ) } } } ; ( $ u : ident : $ ( + $ bound : path ) * => $ seq_in : ty , $ seq_out : ty ; $ t : ident $ var : ident , $ ( $ inner_t : ident $ inner_var : ident ) ,+ ) => { impl_readable_from_line_for_tuples_with_from_iterator ! ( $ u : $ ( + $ bound ) * => $ seq_in , $ seq_out ; $ ( $ inner_t $ inner_var ) ,+ ) ; impl <$ t : Readable , $ ( $ inner_t : Readable ) ,+ , $ u : Readable > ReadableFromLine for ( $ t , $ ( $ inner_t ) ,+ , $ seq_in ) where <$ u as Readable >:: Output : Sized $ ( + $ bound ) * { type Output = ( $ t :: Output , $ ( $ inner_t :: Output ) ,+ , $ seq_out ) ; fn read_line ( line : & str ) -> Result < Self :: Output , String > { let mut n = $ t :: words_count ( ) ; $ ( n += $ inner_t :: words_count ( ) ; ) + # [ allow ( deprecated ) ] let trimmed = line . trim_right_matches ( '\n' ) ; let words_and_rest : Vec <& str > = trimmed . splitn ( n + 1 , ' ' ) . collect ( ) ; if words_and_rest . len ( ) < n { return Err ( format ! ( "line `{}` has {} words, expected at least {}" , line , words_and_rest . len ( ) , n ) ) ; } let words = & words_and_rest [ .. n ] ; let empty_str = "" ; let rest = words_and_rest . get ( n ) . unwrap_or ( & empty_str ) ; let ( $ var , $ ( $ inner_var ) ,* ) = < ( $ t , $ ( $ inner_t ) ,+ ) >:: read_words ( words ) ?; Ok ( ( $ var , $ ( $ inner_var ) ,* , <$ seq_in >:: read_line ( rest ) ? ) ) } } } ; }
#[macro_export]
macro_rules ! readable_collection { ( $ u : ident => $ collection_in : ty , $ collection_out : ty ) => { impl_readable_from_line_for_tuples_with_from_iterator ! ( $ u : => $ collection_in , $ collection_out ; T8 x8 , T7 x7 , T6 x6 , T5 x5 , T4 x4 , T3 x3 , T2 x2 , T1 x1 ) ; } ; ( $ u : ident : $ ( $ bound : path ) ,* => $ collection_in : ty , $ collection_out : ty ) => { impl_readable_from_line_for_tuples_with_from_iterator ! ( $ u : $ ( + $ bound ) * => $ collection_in , $ collection_out ; T8 x8 , T7 x7 , T6 x6 , T5 x5 , T4 x4 , T3 x3 , T2 x2 , T1 x1 ) ; } }
readable_collection ! ( U => Vec < U >, Vec < U :: Output > ) ;
readable_collection ! ( U => std :: collections :: VecDeque < U >, std :: collections :: VecDeque < U :: Output > ) ;
readable_collection ! ( U : Eq , std :: hash :: Hash => std :: collections :: HashSet < U >, std :: collections :: HashSet < U :: Output > ) ;
readable_collection ! ( U : Ord => std :: collections :: BTreeSet < U >, std :: collections :: BTreeSet < U :: Output > ) ;
readable_collection ! ( U : Ord => std :: collections :: BinaryHeap < U >, std :: collections :: BinaryHeap < U :: Output > ) ;
pub fn read<T: ReadableFromLine>() -> T::Output {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).unwrap();
    T::read_line(&line).unwrap()
}
#[macro_export]
macro_rules ! read { ( ) => { let mut line = String :: new ( ) ; std :: io :: stdin ( ) . read_line ( & mut line ) . unwrap ( ) ; } ; ( $ pat : pat = $ t : ty ) => { let $ pat = read ::<$ t > ( ) ; } ; ( $ ( $ pat : pat = $ t : ty ) ,+ ) => { read ! ( ( $ ( $ pat ) ,* ) = ( $ ( $ t ) ,* ) ) ; } ; }
#[macro_export]
macro_rules ! readls { ( $ ( $ pat : pat = $ t : ty ) ,+ ) => { $ ( read ! ( $ pat = $ t ) ; ) * } ; }
pub fn readx<T: ReadableFromLine>() -> Vec<T::Output> {
    use std::io::{self, BufRead};
    let stdin = io::stdin();
    let result = stdin
        .lock()
        .lines()
        .map(|line_result| {
            let line = line_result.expect("read from stdin failed");
            T::read_line(&line).unwrap()
        })
        .collect();
    result
}
#[macro_export]
macro_rules ! readx_loop { ( |$ pat : pat = $ t : ty | $ body : expr ) => { { use std :: io :: BufRead ; let stdin = std :: io :: stdin ( ) ; for line in stdin . lock ( ) . lines ( ) { let line = line . expect ( "read from stdin failed" ) ; let $ pat = <$ t >:: read_line ( & line ) . unwrap ( ) ; $ body } } } ; ( |$ ( $ pat : pat = $ t : ty ) ,*| $ body : expr ) => { readx_loop ! ( | ( $ ( $ pat ) ,* ) = ( $ ( $ t ) ,* ) | $ body ) ; } ; }
pub fn readn<T: ReadableFromLine>(n: usize) -> Vec<T::Output> {
    use std::io::{self, BufRead};
    let stdin = io::stdin();
    let result: Vec<T::Output> = stdin
        .lock()
        .lines()
        .take(n)
        .map(|line_result| {
            let line = line_result.expect("read from stdin failed");
            T::read_line(&line).unwrap()
        })
        .collect();
    if result.len() < n {
        panic!(
            "expected reading {} lines, but only {} lines are read",
            n,
            result.len()
        );
    }
    result
}
#[macro_export]
macro_rules ! readn_loop { ( $ n : expr , |$ pat : pat = $ t : ty | $ body : expr ) => { { use std :: io :: BufRead ; let stdin = std :: io :: stdin ( ) ; let mut lock = stdin . lock ( ) ; for _ in 0 ..$ n { let mut line = String :: new ( ) ; lock . read_line ( & mut line ) . expect ( "read from stdin failed" ) ; let $ pat = <$ t >:: read_line ( & line ) . unwrap ( ) ; $ body } } } ; ( $ n : expr , |$ ( $ pat : pat = $ t : ty ) ,*| $ body : expr ) => { readn_loop ! ( $ n , | ( $ ( $ pat ) ,* ) = ( $ ( $ t ) ,* ) | $ body ) ; } ; }
pub trait Words {
    fn read<T: Readable>(&self) -> T::Output;
}
impl<'a> Words for [&'a str] {
    fn read<T: Readable>(&self) -> T::Output {
        T::read_words(self).unwrap()
    }
}
impl<'a> Words for &'a str {
    fn read<T: Readable>(&self) -> T::Output {
        T::read_words(&[self]).unwrap()
    }
}

macro_rules! forward_ref_unop {
    ( impl $ op : ident , $ method : ident for $ t : ty ) => {
        impl std::ops::$op for &$t {
            type Output = <$t as std::ops::$op>::Output;
            fn $method(self) -> <$t as std::ops::$op>::Output {
                std::ops::$op::$method(*self)
            }
        }
    };
}
macro_rules! forward_ref_binop {
    ( impl $ op : ident , $ method : ident for $ t : ty , $ u : ty ) => {
        impl<'a> std::ops::$op<$u> for &'a $t {
            type Output = <$t as std::ops::$op<$u>>::Output;
            fn $method(self, other: $u) -> <$t as std::ops::$op<$u>>::Output {
                std::ops::$op::$method(*self, other)
            }
        }
        impl std::ops::$op<&$u> for $t {
            type Output = <$t as std::ops::$op<$u>>::Output;
            fn $method(self, other: &$u) -> <$t as std::ops::$op<$u>>::Output {
                std::ops::$op::$method(self, *other)
            }
        }
        impl std::ops::$op<&$u> for &$t {
            type Output = <$t as std::ops::$op<$u>>::Output;
            fn $method(self, other: &$u) -> <$t as std::ops::$op<$u>>::Output {
                std::ops::$op::$method(*self, *other)
            }
        }
    };
}
macro_rules! forward_ref_op_assign {
    ( impl $ op : ident , $ method : ident for $ t : ty , $ u : ty ) => {
        impl std::ops::$op<&$u> for $t {
            fn $method(&mut self, other: &$u) {
                std::ops::$op::$method(self, *other);
            }
        }
    };
}
pub trait PrimitiveInteger:
Sized
    + Ord
    + std::ops::Add<Output = Self>
    + std::ops::Sub<Output = Self>
    + std::ops::Div<Output = Self>
{
    fn one() -> Self;
    fn abs_diff(self, rhs: Self) -> Self;
    fn rem_euclid(self, rhs: Self) -> Self;
}
macro_rules ! impl_primitive_integer { ( $ ( $ t : ty ) * ) => { $ ( impl PrimitiveInteger for $ t { fn one ( ) -> $ t { 1 } fn abs_diff ( self , rhs : $ t ) -> $ t { if self < rhs { rhs - self } else { self - rhs } } # [ allow ( unused_comparisons ) ] fn rem_euclid ( self , rhs : $ t ) -> $ t { let r = self % rhs ; if r < 0 { if rhs < 0 { r - rhs } else { r + rhs } } else { r } } } ) * } }
impl_primitive_integer ! ( u8 u16 u32 u64 usize i8 i16 i32 i64 isize ) ;
pub trait PrimitiveUnsigned: PrimitiveInteger {
    fn ceil_div(self, rhs: Self) -> Self;
    fn round_div(self, rhs: Self) -> Self;
    fn log2(self) -> Option<Self>;
    fn ceil_log2(self) -> Option<Self>;
    fn sqrt(self) -> Self;
}
macro_rules ! impl_primitive_unsigned { ( $ ( $ t : ty ) * ) => { $ ( impl PrimitiveUnsigned for $ t { fn ceil_div ( self , rhs : $ t ) -> $ t { ( self + rhs - 1 ) / rhs } fn round_div ( self , rhs : $ t ) -> $ t { ( self + rhs / 2 ) / rhs } fn log2 ( mut self ) -> Option <$ t > { if self == 0 { None } else { let mut ans = 0 ; while self > 1 { ans += 1 ; self /= 2 ; } Some ( ans ) } } fn ceil_log2 ( self ) -> Option <$ t > { self . log2 ( ) . map ( | x | { ( self + ( ( 1 << x ) - 1 ) ) . log2 ( ) . unwrap ( ) } ) } fn sqrt ( self ) -> $ t { ( self as f64 ) . sqrt ( ) as $ t } } ) * } }
impl_primitive_unsigned ! ( u8 u16 u32 u64 usize ) ;
pub fn gcd(a: u64, b: u64) -> u64 {
    if b == 0 {
        a
    } else {
        gcd(b, a % b)
    }
}
pub fn bezout(a: i64, b: i64) -> (i64, i64, u64) {
    let (x, y, g) = bezout_sub((a * a.signum()) as u64, (b * b.signum()) as u64);
    (x * a.signum(), y * b.signum(), g)
}
fn bezout_sub(a: u64, b: u64) -> (i64, i64, u64) {
    if b == 0 {
        (1, 0, a)
    } else {
        let m = (a / b) as i64;
        let (x, y, g) = bezout_sub(b, a % b);
        (y, x - m * y, g)
    }
}

fn divs(n: u64) -> Vec<u64> {
    let mut res = Vec::new();
    for d in 2..((n as f64).sqrt() as u64)+1 {
        if n % d == 0 {
            res.push(d);
            if n != d*d {
                res.push(n / d);
            }
        }
    }
    res
}

fn main() {
    read!(n = u64);
    let ans = divs(n).into_iter().fold(n, |acc, d| gcd(acc, d));
    println!("{}", ans);
}


use std::io::stdin;
use std::collections::{HashSet, BTreeSet};

macro_rules! readln {
        () => {{ let mut line = String::new(); stdin().read_line(&mut line).unwrap(); line }};
        ($type:ty) => {{ readln!().split_whitespace().next().unwrap().parse::<$type>().unwrap() }};
        (|$type_vec:ty|) => {{ readln!().split_whitespace().map(|it| it.parse().unwrap()).collect::<Vec<$type_vec>>() }};
        ($($type:ty),*) => {{ let line = readln!(); let mut iter = line.split_whitespace(); ($(iter.next().unwrap().parse::<$type>().unwrap(),)*) }};
        ($($type:ty),*, |$type_vec:ty|) => {{ let line = readln!(); let mut iter = line.split_whitespace();
            ($(iter.next().unwrap().parse::<$type>().unwrap(),)*iter.map(|it| it.parse().unwrap()).collect::<Vec<$type_vec>>(),)}};
}

fn re2(mut n: u64) -> BTreeSet<u64> {
    let mut res = BTreeSet::new();
    let mut mb = BTreeSet::new();
    let copy = n;
    let mut i = 2;
    while n != 1 && i * i <= copy && res.len() != 2 {
        if n % i == 0 {
            n /= i;
            res.insert(i);
            mb.insert(copy / i);
        } else {
            i += 1;
        }
    }
    mb.insert(n);
    res.remove(&1);
    if res.len() == 2 {
        return res;
    }
    mb.iter().for_each(|it| {
        let mut flag = true;
        for j in res.iter() {
            if *it % *j == 0 {
                flag = false;
            }
        }
        if flag {
            res.insert(*it);
        }
    });
    res.remove(&1);
    if res.is_empty() {
        res.insert(copy);
        return res;
    }

    res
}

fn main() {
    let mut n = readln!(u64);

    let res = re2(n);

    if res.is_empty() {
        println!("{}", n);
    } else if res.len() == 1 {
        println!("{}", res.iter().next().unwrap());
    } else {
        println!("1")
    }
}


#![allow(unused_imports)]
#![allow(non_snake_case, unused)]

use std::cmp::*;
use std::collections::*;
use std::ops::*;

macro_rules! eprint {
	($($t:tt)*) => {{
		use ::std::io::Write;
		let _ = write!(::std::io::stderr(), $($t)*);
	}};
}
macro_rules! eprintln {
	() => { eprintln!(""); };
	($($t:tt)*) => {{
		use ::std::io::Write;
		let _ = writeln!(::std::io::stderr(), $($t)*);
	}};
}
macro_rules! dbg {
	($v:expr) => {{
		let val = $v;
		eprintln!("[{}:{}] {} = {:?}", file!(), line!(), stringify!($v), val);
		val
	}}
}

macro_rules! mat {
	($($e:expr),*) => { Vec::from(vec![$($e),*]) };
	($($e:expr,)*) => { Vec::from(vec![$($e),*]) };
	($e:expr; $d:expr) => { Vec::from(vec![$e; $d]) };
	($e:expr; $d:expr $(; $ds:expr)+) => { Vec::from(vec![mat![$e $(; $ds)*]; $d]) };
}

macro_rules! ok {
	($a:ident$([$i:expr])*.$f:ident()$(@$t:ident)*) => {
		$a$([$i])*.$f($($t),*)
	};
	($a:ident$([$i:expr])*.$f:ident($e:expr$(,$es:expr)*)$(@$t:ident)*) => { {
		let t = $e;
		ok!($a$([$i])*.$f($($es),*)$(@$t)*@t)
	} };
}

pub fn readln() -> String {
	let mut line = String::new();
	::std::io::stdin().read_line(&mut line).unwrap_or_else(|e| panic!("{}", e));
	line
}

macro_rules! read {
	($($t:tt),*; $n:expr) => {{
		let stdin = ::std::io::stdin();
		let ret = ::std::io::BufRead::lines(stdin.lock()).take($n).map(|line| {
			let line = line.unwrap();
			let mut it = line.split_whitespace();
			_read!(it; $($t),*)
		}).collect::<Vec<_>>();
		ret
	}};
	($($t:tt),*) => {{
		let line = readln();
		let mut it = line.split_whitespace();
		_read!(it; $($t),*)
	}};
}

macro_rules! _read {
	($it:ident; [char]) => {
		_read!($it; String).chars().collect::<Vec<_>>()
	};
	($it:ident; [u8]) => {
		Vec::from(_read!($it; String).into_bytes())
	};
	($it:ident; usize1) => {
		$it.next().unwrap_or_else(|| panic!("input mismatch")).parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1
	};
	($it:ident; [usize1]) => {
		$it.map(|s| s.parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1).collect::<Vec<_>>()
	};
	($it:ident; [$t:ty]) => {
		$it.map(|s| s.parse::<$t>().unwrap_or_else(|e| panic!("{}", e))).collect::<Vec<_>>()
	};
	($it:ident; $t:ty) => {
		$it.next().unwrap_or_else(|| panic!("input mismatch")).parse::<$t>().unwrap_or_else(|e| panic!("{}", e))
	};
	($it:ident; $($t:tt),+) => {
		($(_read!($it; $t)),*)
	};
}

pub fn main() {
	let _ = ::std::thread::Builder::new().name("run".to_string()).stack_size(32 * 1024 * 1024).spawn(run).unwrap().join();
}

const MOD: u32 = 1_000_000_007;
const INF: i64 = std::i64::MAX;

pub trait SetMinMax {
	fn setmin(&mut self, v: Self) -> bool;
	fn setmax(&mut self, v: Self) -> bool;
}
impl<T> SetMinMax for T where T: PartialOrd {
	fn setmin(&mut self, v: T) -> bool {
		*self > v && { *self = v; true }
	}
	fn setmax(&mut self, v: T) -> bool {
		*self < v && { *self = v; true }
	}
}

use std::cmp::Ordering;

/// Equivalent to std::lowerbound and std::upperbound in c++
pub trait BinarySearch<T> {
    fn lower_bound(&self, x: &T) -> usize;
    fn upper_bound(&self, x: &T) -> usize;
}

impl<T: Ord> BinarySearch<T> for [T] {
    // 配列a内のv以上の最小のindex
    fn lower_bound(&self, x: &T) -> usize {
        let mut low = 0;
        let mut high = self.len();

        while low != high {
            let mid = (low + high) / 2;
            match self[mid].cmp(x) {
                Ordering::Less => {
                    low = mid + 1;
                }
                Ordering::Equal | Ordering::Greater => {
                    high = mid;
                }
            }
        }
        low
    }
    // 配列a内のvより大きいの最小のindex
    fn upper_bound(&self, x: &T) -> usize {
        let mut low = 0;
        let mut high = self.len();

        while low != high {
            let mid = (low + high) / 2;
            match self[mid].cmp(x) {
                Ordering::Less | Ordering::Equal => {
                    low = mid + 1;
                }
                Ordering::Greater => {
                    high = mid;
                }
            }
        }
        low
    }
}

fn swap(a: usize, b: usize, sv: &mut [char], tv: &mut [char]) {
	let tmp = sv[a];
	sv[a] = tv[b];
	tv[b] = tmp;
}

fn solve() {
	let n = read!(i64);
	let mut sum = 0;
	let mut v = vec![];
	if n==1 {
		println!("{}", 1);
		return;
	}
	for i in 2..((n as f64).sqrt() as i64+1) {
		if n%i==0 {
			sum+=2;
			v.push(i);
			v.push(n/i);
		}
	}
	if sum==0 {
		println!("{}", n);
		return;
	}
	let mi = v[0];
	let mut flag = true;
	for &i in &v {
		if i%mi!=0 {flag=false;}
	}
	if !flag {println!("{}", 1);}
	else{ println!("{}", mi);}

}

fn run() {
    solve();
}


struct Scan {
    buffer: std::collections::VecDeque<String>
}

impl Scan {
    fn new() -> Scan {
        Scan { buffer: std::collections::VecDeque::new() }
    }

    fn next<T: std::str::FromStr>(&mut self)-> T {
        loop {
            if let Some(token) = self.buffer.pop_front() {
                break token.parse::<T>().ok().unwrap();
            }
            let mut line = String::new();
            std::io::stdin().read_line(&mut line).expect("Fail to read");
            self.buffer = line.split_whitespace().map(String::from).collect();
        }
    }

}

fn _main() {
    let mut scan = Scan::new();
    let mut _n: u64 = scan.next();
    println!("25");
}

fn main() {
    std::thread::Builder::new()
        .stack_size(1<<23).spawn(_main).unwrap().join().unwrap();
}


#[allow(unused_imports)]
use std::cmp::{max,min};
#[allow(unused_imports)]
use std::collections::{HashMap,HashSet,VecDeque};

#[allow(unused_macros)]
macro_rules! readln {
    () => {{
        use std::io;

        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim().to_string()
    }};
    ( $t:ty ) => {{
        let input = readln!();
        input.parse::<$t>().unwrap()
    }};
    ( $( $t:ty ),+ ) => {{
        let input = readln!();
        let mut input = input.split_whitespace();
        (
            $(
                input.next().unwrap().parse::<$t>().unwrap(),
            )+
        )
    }}
}

#[allow(unused_macros)]
macro_rules! readvec {
    ( $t:ty ) => {{
        let input = readln!();
        let mut input = input.split_whitespace();
        let mut result = Vec::new();
        for elem in input {
            result.push(elem.parse::<$t>().unwrap());
        }
        result
    }}
}

fn main() {
    readln!();
    println!("25");
}


/*
    Geometry, math - https://codeforces.com/problemset/problem/1369/A
    Completed: 4/7/20 14:06
*/

use std::io;

fn main() {
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();

    // This is so retarded
    println!("25");

}


#[allow(unused_imports)]
use std::io;
use std::mem::size_of_val;
use std::cmp::{max, min};
use std::rc::Rc;
use std::collections::btree_map::BTreeMap;
use std::io::{Write, BufRead};
use std::collections::HashMap;
use std::ptr::write_volatile;
use std::ops::Add;

#[allow(dead_code)]
fn gets() -> String {
    let mut s = String::new();
    io::stdin().read_line(&mut s).unwrap();
    s.trim().to_string()
}

#[allow(unused)]
fn read_strings() -> Vec<String> {
    let mut string: String = String::new();
    std::io::stdin().read_line(&mut string).unwrap();
    let mut v = Vec::new();
    for value in string.split_whitespace() {
        v.push(value.to_string());
    }
    v
}

#[allow(unused)]
fn read_array_i32() -> Vec<i32> {
    let mut string: String = String::new();
    std::io::stdin().read_line(&mut string).unwrap();
    string.split_whitespace().map(|x| x.parse::<i32>().unwrap()).collect()
}

#[allow(unused_macros)]
macro_rules! read_array {
    ( $ty:ty, ... ) => {
        gets().split_whitespace().map(|x| x.parse::<$ty>().unwrap())
    };
    ( $($ty:ty),* ) => {{
        let line = gets();
        let mut it = line.split_whitespace();
        ( $(it.next().unwrap().parse::<$ty>().unwrap(),)* )
    }}
}

// mod math;
// mod binary_search;
// mod graph;
// mod structure;
// mod fibonacci;
// mod string;
// mod permutations;

// mod patterns;

#[allow(dead_code)]
fn memory_properties<T>(value: &T)
    where
        T: std::fmt::Display + ?Sized,
{
    println!(
        "Variable address in memory = {:p}, Allocated bytes for type = {}",
        value,
        size_of_val(value)
    );
}

#[allow(unused_macros)]
macro_rules! sum {
    ($($x:expr), *) => {
        {
            let mut res = 0;
            $(res += $x;)*
            res
        }
    };
}

fn main() {
    use std::io::Write;
    let out = std::io::stdout();
    let mut out = std::io::BufWriter::new(out.lock());

    gets();
    writeln!(out, "{}", 25);

    // writeln!(out, "{}", "Hello Rust").unwrap();
}


// ---------- begin ModInt ----------
// モンゴメリ乗算を用いる
// ほぼCodeforces用
// 注意
// new_unchecked は値xが 0 <= x < modulo であることを仮定
// ModInt の中身は正規化された値で持ってるので直接読んだり書いたりするとぶっ壊れる
// 奇素数のみ
mod modint {

    use std::marker::*;
    use std::ops::*;

    pub trait Modulo {
        fn modulo() -> u32;
        fn rem() -> u32;
        fn ini() -> u64;
        fn reduce(x: u64) -> u32 {
            debug_assert!(x < (Self::modulo() as u64) << 32);
            let b = (x as u32 * Self::rem()) as u64;
            let t = x + b * Self::modulo() as u64;
            let mut c = (t >> 32) as u32;
            if c >= Self::modulo() {
                c -= Self::modulo();
            }
            c as u32
        }
    }

    #[allow(dead_code)]
    pub enum Mod1_000_000_007 {}

    impl Modulo for Mod1_000_000_007 {
        fn modulo() -> u32 {
            1_000_000_007
        }
        fn rem() -> u32 {
            2226617417
        }
        fn ini() -> u64 {
            582344008
        }
    }

    #[allow(dead_code)]
    pub enum Mod998_244_353 {}

    impl Modulo for Mod998_244_353 {
        fn modulo() -> u32 {
            998_244_353
        }
        fn rem() -> u32 {
            998244351
        }
        fn ini() -> u64 {
            932051910
        }
    }

    #[allow(dead_code)]
    pub fn generate_umekomi_modulo(p: u32) {
        assert!(
            p < (1 << 31)
                && p > 2
                && p & 1 == 1
                && (2u32..).take_while(|v| v * v <= p).all(|k| p % k != 0)
        );
        let mut t = 1u32;
        let mut s = !p + 1;
        let mut n = !0u32 >> 2;
        while n > 0 {
            if n & 1 == 1 {
                t *= s;
            }
            s *= s;
            n >>= 1;
        }
        let mut ini = (1u64 << 32) % p as u64;
        ini = (ini << 32) % p as u64;
        assert!(t * p == !0);
        println!("pub enum Mod{} {{}}", p);
        println!("impl Modulo for Mod{} {{", p);
        println!("    fn modulo() -> u32 {{");
        println!("        {}", p);
        println!("    }}");
        println!("    fn rem() -> u32 {{");
        println!("        {}", t);
        println!("    }}");
        println!("    fn ini() -> u64 {{");
        println!("        {}", ini);
        println!("    }}");
        println!("}}");
        let mut f = vec![];
        let mut n = p - 1;
        for i in 2.. {
            if i * i > n {
                break;
            }
            if n % i == 0 {
                f.push(i);
                while n % i == 0 {
                    n /= i;
                }
            }
        }
        if n > 1 {
            f.push(n);
        }
        let mut order = 1;
        let mut n = p - 1;
        while n % 2 == 0 {
            n /= 2;
            order <<= 1;
        }
        let z = (2u64..)
            .find(|z| {
                f.iter()
                    .all(|f| mod_pow(*z, ((p - 1) / *f) as u64, p as u64) != 1)
            })
            .unwrap();
        let zeta = mod_pow(z, ((p - 1) / order) as u64, p as u64);
        println!("impl transform::NTTFriendly for Mod{} {{", p);
        println!("    fn order() -> usize {{");
        println!("        {}", order);
        println!("    }}");
        println!("    fn zeta() -> u32 {{");
        println!("        {}", zeta);
        println!("    }}");
        println!("}}");
    }

    pub struct ModInt<T>(u32, PhantomData<T>);

    impl<T> Clone for ModInt<T> {
        fn clone(&self) -> Self {
            ModInt::build(self.0)
        }
    }

    impl<T> Copy for ModInt<T> {}

    impl<T: Modulo> Add for ModInt<T> {
        type Output = ModInt<T>;
        fn add(self, rhs: Self) -> Self::Output {
            let mut d = self.0 + rhs.0;
            if d >= T::modulo() {
                d -= T::modulo();
            }
            Self::build(d)
        }
    }

    impl<T: Modulo> AddAssign for ModInt<T> {
        fn add_assign(&mut self, rhs: Self) {
            *self = *self + rhs;
        }
    }

    impl<T: Modulo> Sub for ModInt<T> {
        type Output = ModInt<T>;
        fn sub(self, rhs: Self) -> Self::Output {
            let mut d = self.0 - rhs.0;
            if self.0 < rhs.0 {
                d += T::modulo();
            }
            Self::build(d)
        }
    }

    impl<T: Modulo> SubAssign for ModInt<T> {
        fn sub_assign(&mut self, rhs: Self) {
            *self = *self - rhs;
        }
    }

    impl<T: Modulo> Mul for ModInt<T> {
        type Output = ModInt<T>;
        fn mul(self, rhs: Self) -> Self::Output {
            Self::build(T::reduce(self.0 as u64 * rhs.0 as u64))
        }
    }

    impl<T: Modulo> MulAssign for ModInt<T> {
        fn mul_assign(&mut self, rhs: Self) {
            *self = *self * rhs;
        }
    }

    impl<T: Modulo> Neg for ModInt<T> {
        type Output = ModInt<T>;
        fn neg(self) -> Self::Output {
            if self.0 == 0 {
                Self::zero()
            } else {
                Self::build(T::modulo() - self.0)
            }
        }
    }

    impl<T: Modulo> std::fmt::Display for ModInt<T> {
        fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
            write!(f, "{}", self.get())
        }
    }

    impl<T: Modulo> std::fmt::Debug for ModInt<T> {
        fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
            write!(f, "{}", self.get())
        }
    }

    impl<T: Modulo> std::str::FromStr for ModInt<T> {
        type Err = std::num::ParseIntError;
        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let val = s.parse::<u32>()?;
            Ok(ModInt::new(val))
        }
    }

    impl<T: Modulo> From<usize> for ModInt<T> {
        fn from(val: usize) -> ModInt<T> {
            ModInt::new_unchecked((val % T::modulo() as usize) as u32)
        }
    }

    impl<T: Modulo> From<u64> for ModInt<T> {
        fn from(val: u64) -> ModInt<T> {
            ModInt::new_unchecked((val % T::modulo() as u64) as u32)
        }
    }

    impl<T: Modulo> From<i64> for ModInt<T> {
        fn from(val: i64) -> ModInt<T> {
            let m = T::modulo() as i64;
            ModInt::new((val % m + m) as u32)
        }
    }

    #[allow(dead_code)]
    impl<T> ModInt<T> {
        fn build(d: u32) -> Self {
            ModInt(d, PhantomData)
        }
        pub fn zero() -> Self {
            Self::build(0)
        }
        pub fn is_zero(&self) -> bool {
            self.0 == 0
        }
    }

    #[allow(dead_code)]
    impl<T: Modulo> ModInt<T> {
        pub fn new_unchecked(d: u32) -> Self {
            Self::build(T::reduce(d as u64 * T::ini()))
        }
        pub fn new(d: u32) -> Self {
            Self::new_unchecked(d % T::modulo())
        }
        pub fn one() -> Self {
            Self::new_unchecked(1)
        }
        pub fn get(&self) -> u32 {
            T::reduce(self.0 as u64)
        }
        pub fn pow(&self, mut n: u64) -> Self {
            let mut t = Self::one();
            let mut s = *self;
            while n > 0 {
                if n & 1 == 1 {
                    t *= s;
                }
                s *= s;
                n >>= 1;
            }
            t
        }
        pub fn inv(&self) -> Self {
            assert!(!self.is_zero());
            self.pow((T::modulo() - 2) as u64)
        }
    }

    pub fn mod_pow(mut r: u64, mut n: u64, m: u64) -> u64 {
        let mut t = 1 % m;
        while n > 0 {
            if n & 1 == 1 {
                t = t * r % m;
            }
            r = r * r % m;
            n >>= 1;
        }
        t
    }
}
// ---------- end ModInt ----------
// ---------- begin Precalc ----------
mod precalc {
    use super::modint::*;
    #[allow(dead_code)]
    pub struct Precalc<T> {
        inv: Vec<ModInt<T>>,
        fact: Vec<ModInt<T>>,
        ifact: Vec<ModInt<T>>,
    }
    #[allow(dead_code)]
    impl<T: Modulo> Precalc<T> {
        pub fn new(n: usize) -> Precalc<T> {
            let mut inv = vec![ModInt::one(); n + 1];
            let mut fact = vec![ModInt::one(); n + 1];
            let mut ifact = vec![ModInt::one(); n + 1];
            for i in 2..(n + 1) {
                fact[i] = fact[i - 1] * ModInt::new_unchecked(i as u32);
            }
            ifact[n] = fact[n].inv();
            if n > 0 {
                inv[n] = ifact[n] * fact[n - 1];
            }
            for i in (1..n).rev() {
                ifact[i] = ifact[i + 1] * ModInt::new_unchecked((i + 1) as u32);
                inv[i] = ifact[i] * fact[i - 1];
            }
            Precalc {
                inv: inv,
                fact: fact,
                ifact: ifact,
            }
        }
        pub fn inv(&self, n: usize) -> ModInt<T> {
            assert!(n > 0);
            self.inv[n]
        }
        pub fn fact(&self, n: usize) -> ModInt<T> {
            self.fact[n]
        }
        pub fn ifact(&self, n: usize) -> ModInt<T> {
            self.ifact[n]
        }
        pub fn perm(&self, n: usize, k: usize) -> ModInt<T> {
            if k > n {
                return ModInt::zero();
            }
            self.fact[n] * self.ifact[n - k]
        }
        pub fn comb(&self, n: usize, k: usize) -> ModInt<T> {
            if k > n {
                return ModInt::zero();
            }
            self.fact[n] * self.ifact[k] * self.ifact[n - k]
        }
    }
}
// ---------- end Precalc ----------

use modint::*;

pub trait NTTFriendly: modint::Modulo {
    fn order() -> usize;
    fn zeta() -> u32;
}

type M = ModInt<Mod998_244_353>;

impl NTTFriendly for Mod998_244_353 {
    fn order() -> usize {
        8388608
    }
    fn zeta() -> u32 {
        15311432
    }
}

// 列に対する命令をテキトーに詰めあわせ
// modint, primitive type の２つあたりで使うことを想定
// +, -, *
// zero を要求してないのに仮定してる場所がある
//
// 何も考えずに書き始めたらいろいろよくわからないことになった
// 整理
// 長さが等しいときの加算、減算、dot積はok
// 長さが異なるときはどうする？
// 0埋めされてるというイメージなので
// 加算、減算は素直だがdot積はイマイチ
// dot積だけ長さが等しいとしておく?
// あるいは0埋めのイメージを消すか

use std::ops::*;

pub trait Zero: Sized + Add<Output = Self> {
    fn zero() -> Self;
}

pub fn zero<T: Zero>() -> T {
    T::zero()
}

impl<T: Modulo> Zero for ModInt<T> {
    fn zero() -> Self {
        Self::zero()
    }
}

impl Zero for usize {
    fn zero() -> Self {
        0
    }
}

pub trait ArrayAdd {
    type Item;
    fn add(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;
}

impl<T> ArrayAdd for [T]
where
    T: Zero + Copy,
{
    type Item = T;
    fn add(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {
        let mut c = vec![T::zero(); self.len().max(rhs.len())];
        c[..self.len()].copy_from_slice(self);
        c.add_assign(rhs);
        c
    }
}

pub trait ArrayAddAssign {
    type Item;
    fn add_assign(&mut self, rhs: &[Self::Item]);
}

impl<T> ArrayAddAssign for [T]
where
    T: Add<Output = T> + Copy,
{
    type Item = T;
    fn add_assign(&mut self, rhs: &[Self::Item]) {
        assert!(self.len() >= rhs.len());
        self.iter_mut().zip(rhs).for_each(|(x, a)| *x = *x + *a);
    }
}

impl<T> ArrayAddAssign for Vec<T>
where
    T: Zero + Add<Output = T> + Copy,
{
    type Item = T;
    fn add_assign(&mut self, rhs: &[Self::Item]) {
        if self.len() < rhs.len() {
            self.resize(rhs.len(), T::zero());
        }
        self.as_mut_slice().add_assign(rhs);
    }
}

pub trait ArraySub {
    type Item;
    fn sub(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;
}

impl<T> ArraySub for [T]
where
    T: Zero + Sub<Output = T> + Copy,
{
    type Item = T;
    fn sub(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {
        let mut c = vec![T::zero(); self.len().max(rhs.len())];
        c[..self.len()].copy_from_slice(self);
        c.sub_assign(rhs);
        c
    }
}

pub trait ArraySubAssign {
    type Item;
    fn sub_assign(&mut self, rhs: &[Self::Item]);
}

impl<T> ArraySubAssign for [T]
where
    T: Sub<Output = T> + Copy,
{
    type Item = T;
    fn sub_assign(&mut self, rhs: &[Self::Item]) {
        assert!(self.len() >= rhs.len());
        self.iter_mut().zip(rhs).for_each(|(x, a)| *x = *x - *a);
    }
}

impl<T> ArraySubAssign for Vec<T>
where
    T: Zero + Sub<Output = T> + Copy,
{
    type Item = T;
    fn sub_assign(&mut self, rhs: &[Self::Item]) {
        if self.len() < rhs.len() {
            self.resize(rhs.len(), T::zero());
        }
        self.as_mut_slice().sub_assign(rhs);
    }
}

pub trait ArrayDot {
    type Item;
    fn dot(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;
}

impl<T> ArrayDot for [T]
where
    T: Mul<Output = T> + Copy,
{
    type Item = T;
    fn dot(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {
        assert!(self.len() == rhs.len());
        self.iter().zip(rhs).map(|p| *p.0 * *p.1).collect()
    }
}

pub trait ArrayDotAssign {
    type Item;
    fn dot_assign(&mut self, rhs: &[Self::Item]);
}

impl<T> ArrayDotAssign for [T]
where
    T: MulAssign + Copy,
{
    type Item = T;
    fn dot_assign(&mut self, rhs: &[Self::Item]) {
        assert!(self.len() == rhs.len());
        self.iter_mut().zip(rhs).for_each(|(x, a)| *x *= *a);
    }
}

pub trait ArrayMul {
    type Item;
    fn mul(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;
}

impl<T> ArrayMul for [T]
where
    T: Zero + Mul<Output = T> + Copy,
{
    type Item = T;
    fn mul(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {
        if self.is_empty() || rhs.is_empty() {
            return vec![];
        }
        let mut res = vec![zero(); self.len() + rhs.len() - 1];
        for (i, a) in self.iter().enumerate() {
            for (c, b) in res[i..].iter_mut().zip(rhs) {
                *c = *c + *a * *b;
            }
        }
        res
    }
}

pub trait ArrayNTT {
    type Item;
    fn ntt(&mut self);
    fn intt(&mut self);
    fn multiply(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;
}

impl<T> ArrayNTT for [ModInt<T>]
where
    T: NTTFriendly,
{
    type Item = ModInt<T>;
    fn ntt(&mut self) {
        let f = self;
        let n = f.len();
        assert!(n.count_ones() == 1);
        assert!(n <= T::order());
        let len = n.trailing_zeros() as usize;
        let mut es = [ModInt::zero(); 30];
        let mut ies = [ModInt::zero(); 30];
        let mut sum_e = [ModInt::zero(); 30];
        let cnt2 = T::order().trailing_zeros() as usize;
        let mut e = ModInt::new_unchecked(T::zeta());
        let mut ie = e.inv();
        for i in (2..=cnt2).rev() {
            es[i - 2] = e;
            ies[i - 2] = ie;
            e = e * e;
            ie = ie * ie;
        }
        let mut now = ModInt::one();
        for i in 0..(cnt2 - 1) {
            sum_e[i] = es[i] * now;
            now *= ies[i];
        }
        for ph in 1..=len {
            let p = 1 << (len - ph);
            let mut now = ModInt::one();
            for (i, f) in f.chunks_exact_mut(2 * p).enumerate() {
                let (x, y) = f.split_at_mut(p);
                for (x, y) in x.iter_mut().zip(y.iter_mut()) {
                    let l = *x;
                    let r = *y * now;
                    *x = l + r;
                    *y = l - r;
                }
                now *= sum_e[(!i).trailing_zeros() as usize];
            }
        }
    }
    fn intt(&mut self) {
        let f = self;
        let n = f.len();
        assert!(n.count_ones() == 1);
        assert!(n <= T::order());
        let len = n.trailing_zeros() as usize;
        let mut es = [ModInt::zero(); 30];
        let mut ies = [ModInt::zero(); 30];
        let mut sum_ie = [ModInt::zero(); 30];
        let cnt2 = T::order().trailing_zeros() as usize;
        let mut e = ModInt::new_unchecked(T::zeta());
        let mut ie = e.inv();
        for i in (2..=cnt2).rev() {
            es[i - 2] = e;
            ies[i - 2] = ie;
            e = e * e;
            ie = ie * ie;
        }
        let mut now = ModInt::one();
        for i in 0..(cnt2 - 1) {
            sum_ie[i] = ies[i] * now;
            now *= es[i];
        }
        for ph in (1..=len).rev() {
            let p = 1 << (len - ph);
            let mut inow = ModInt::one();
            for (i, f) in f.chunks_exact_mut(2 * p).enumerate() {
                let (x, y) = f.split_at_mut(p);
                for (x, y) in x.iter_mut().zip(y.iter_mut()) {
                    let l = *x;
                    let r = *y;
                    *x = l + r;
                    *y = (l - r) * inow;
                }
                inow *= sum_ie[(!i).trailing_zeros() as usize];
            }
        }
        let ik = ModInt::new_unchecked((T::modulo() + 1) >> 1).pow(len as u64);
        for f in f.iter_mut() {
            *f *= ik;
        }
    }
    fn multiply(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {
        if self.len().min(rhs.len()) <= 32 {
            return self.mul(rhs);
        }
        let size = (self.len() + rhs.len() - 1).next_power_of_two();
        let mut f = vec![ModInt::zero(); size];
        let mut g = vec![ModInt::zero(); size];
        f[..self.len()].copy_from_slice(self);
        g[..rhs.len()].copy_from_slice(rhs);
        f.ntt();
        g.ntt();
        f.dot_assign(&g);
        f.intt();
        f.truncate(self.len() + rhs.len() - 1);
        f
    }
}

pub trait PolynomialOperation {
    type Item;
    fn eval(&self, x: Self::Item) -> Self::Item;
    fn derivative(&self) -> Vec<Self::Item>;
    fn integral(&self) -> Vec<Self::Item>;
}

impl<T: Modulo> PolynomialOperation for [ModInt<T>] {
    type Item = ModInt<T>;
    fn eval(&self, x: Self::Item) -> Self::Item {
        self.iter().rev().fold(ModInt::zero(), |s, a| s * x + *a)
    }
    fn derivative(&self) -> Vec<Self::Item> {
        if self.len() <= 1 {
            return vec![];
        }
        self[1..]
            .iter()
            .enumerate()
            .map(|(k, a)| ModInt::new_unchecked(k as u32 + 1) * *a)
            .collect()
    }
    fn integral(&self) -> Vec<Self::Item> {
        if self.is_empty() {
            return vec![];
        }
        let mut inv = vec![ModInt::one(); self.len() + 1];
        let mut mul = ModInt::zero();
        for i in 1..=self.len() {
            mul += ModInt::one();
            inv[i] = inv[i - 1] * mul;
        }
        let mut prod = inv[self.len()].inv();
        for i in (1..=self.len()).rev() {
            inv[i] = self[i - 1] * inv[i - 1] * prod;
            prod *= mul;
            mul -= ModInt::one();
        }
        inv[0] = ModInt::zero();
        inv
    }
}

pub trait FPSOperation {
    type Item;
    fn inverse(&self, n: usize) -> Vec<Self::Item>;
    fn log(&self, n: usize) -> Vec<Self::Item>;
    fn exp(&self, n: usize) -> Vec<Self::Item>;
}

impl<T: NTTFriendly> FPSOperation for [ModInt<T>] {
    type Item = ModInt<T>;
    fn inverse(&self, n: usize) -> Vec<Self::Item> {
        assert!(self.len() > 0 && !self[0].is_zero());
        let len = n.next_power_of_two();
        assert!(2 * len <= T::order());
        let mut b = vec![ModInt::zero(); n];
        b[0] = self[0].inv();
        let mut f = Vec::with_capacity(2 * len);
        let mut g = Vec::with_capacity(2 * len);
        let mut size = 1;
        while size < n {
            g.clear();
            g.extend(b.iter().take(size));
            g.resize(2 * size, ModInt::zero());
            f.clear();
            f.extend(self.iter().take(2 * size));
            f.resize(2 * size, ModInt::zero());
            f.ntt();
            g.ntt();
            f.dot_assign(&g);
            f.intt();
            f[..size].iter_mut().for_each(|f| *f = ModInt::zero());
            f.ntt();
            f.dot_assign(&g);
            f.intt();
            for (b, g) in b[size..].iter_mut().zip(&f[size..]) {
                *b = *b - *g;
            }
            size *= 2;
        }
        b
    }
    fn log(&self, n: usize) -> Vec<Self::Item> {
        assert!(self.get(0).map_or(false, |p| p.get() == 1));
        let mut b = self.derivative().multiply(&self.inverse(n));
        b.truncate(n - 1);
        let mut b = b.integral();
        b.resize(n, ModInt::zero());
        b
    }
    fn exp(&self, n: usize) -> Vec<Self::Item> {
        assert!(self.get(0).map_or(true, |a| a.is_zero()));
        assert!(n <= T::order());
        let mut b = vec![ModInt::one()];
        let mut size = 1;
        while size < n {
            size <<= 1;
            let f = b.log(size);
            let g = self[..self.len().min(size)].sub(&f);
            b = b.multiply(&g).add(&b);
            b.truncate(size);
        }
        b.truncate(n);
        b.resize(n, ModInt::zero());
        b
    }
}

// test
//  yuki907: https://yukicoder.me/submissions/712523
//  hhkb2020: https://atcoder.jp/contests/hhkb2020/submissions/26997806
//

// ---------- begin input macro ----------
// reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};
    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };
    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };
    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };
    ($iter:expr, bytes) => {
        read_value!($iter, String).bytes().collect::<Vec<u8>>()
    };
    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };
    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}
// ---------- end input macro ----------

use std::io::Write;
use std::collections::*;

type Map<K, V> = BTreeMap<K, V>;
type Set<T> = BTreeSet<T>;
type Deque<T> = VecDeque<T>;

fn run() {
    input! {
        n: usize,
        k: usize,
    }
    let pc = precalc::Precalc::new(n * n + k);
    let mut dp = vec![M::zero(); n];
    dp[n - 1] = M::one();
    for i in 0..k {
        let mut next = dp.clone();
        for (j, dp) in dp.iter().enumerate() {
            for a in 1..=j {
                let mut w = *dp;
                w *= pc.comb(j, a);
                w *= M::from(k - i).pow((a * (a - 1) / 2 + a * (n - 1 - j)) as u64);
                next[j - a] += w;
            }
        }
        dp = next;
    }
    println!("{}", dp[0]);
}

fn main() {
    run();
}


use std::vec;
fn ksm(mut a:isize, mut b:isize, c:isize) -> isize {
    a = a%c;
    let mut ret = 1;
    while b >= 1{
        if b % 2 == 1 {
            ret = (ret*a % c) as isize;
        }
        a = a*a % c;
        b /= 2;
    }
    return ret;
}
fn inv(mut a:isize, c:isize) -> isize {
    if a == 0{
        return 1;
    }
    return ksm(a, c-2, c);
}
fn main() {
    let mut input = String::new();
    std::io::stdin().read_line(&mut input);
    let mut n = 0;
    let mut m = 0;
    let mut i = 0;
    let p:isize = 998244353;
    for word in input.split_whitespace(){
        if i == 0 {
            n = word.to_string().parse::<isize>().unwrap();
        }
        if i == 1{
            m = word.to_string().parse::<isize>().unwrap();
        }
        i += 1;
    }
    n -= 1;
    let mut f= vec![vec![0;(m+1) as usize];(n+1) as usize];
    for i in 0..(m+1) as usize {
        f[0][i] = 1;
    }

    let mut jc = vec![1];
    for i in 1..n+2 {
        jc.insert(i as usize, jc[(i-1) as usize] * i %p);
    }

    // println!("{:?}",jc);

    let mut ans = 0;
    for i in 1..(n+1) as usize {
        for j in 1..(m+1) as usize {
            f[i][j] = f[i][j-1];
            for k in 0..i {
                let mut mi = 0;
                let mut t = i - k;
                f[i][j] = (f[i][j] + f[k][j-1]*ksm(m-j as isize+1, (k*t) as isize, p)%p*ksm(m-j as isize+1, (t*(t-1)/2) as isize , p)%p*jc[i]%p*inv(jc[t] as isize, p)%p*inv(jc[k] as isize, p)%p)%p;
            }
        }
    }
    // println!("{:?}", f);
    println!("{}", f[n as usize][m as usize]);
}


#![allow(unused_imports)]
use input::*;
use std::{
    collections::*,
    io::{self, BufWriter, Write},
};
fn run<I: Input, O: Write>(mut ss: I, mut out: O) {
    let t: u32 = 1;
    for _ in 0..t {
        case(&mut ss, &mut out);
    }
}
use mod_int::*;
def_mint!(998244353);
fn case<I: Input, O: Write>(mut ss: I, mut out: O) {
    let (n, k): (usize, usize) = ss.parse();
    let f = fact::Fact::new(n + k);
    let mut dp = vec![mint(0); n + 1];
    dp[1] = mint(1);
    for i in 1..=k {
        let mut dp_next = dp.clone();
        for a in 1..n {
            for b in a + 1..=n {
                let d = b - a;
                let c = d * (a - 1) + d * (d - 1) / 2;
                let w = k - i + 1;
                d!(c, w);
                dp_next[b] += dp[a] * f.binom(b - 1, d) * Mint::from(w).pow(c);
            }
        }
        dp = dp_next;
        d!(dp);
    }
    let ans = dp[n];
    wln!(out, "{}", ans);
}
fn main() {
    let stdin = io::stdin();
    let ss = SplitWs::new(stdin.lock());
    let stdout = io::stdout();
    let out = BufWriter::new(stdout.lock());
    run(ss, out);
}
pub mod fact {
    use super::mod_int::*;
    pub struct Fact<M> {
        f: Vec<ModInt<M>>,
        finv: Vec<ModInt<M>>,
    }
    impl<M: Modulo> Fact<M> {
        pub fn new(n: usize) -> Self {
            let mut f = vec![ModInt::new(0); n + 1];
            f[0] = ModInt::new(1);
            for i in 1..=n {
                f[i] = ModInt::new(i as u32) * f[i - 1];
            }
            let mut finv = vec![ModInt::new(0); n + 1];
            finv[n] = f[n].inv();
            for i in (1..=n).rev() {
                finv[i - 1] = finv[i] * ModInt::new(i as u32);
            }
            Self { f, finv }
        }
        pub fn fact(&self, x: usize) -> ModInt<M> {
            self.f[x]
        }
        pub fn fact_inv(&self, x: usize) -> ModInt<M> {
            self.finv[x]
        }
        pub fn binom(&self, n: usize, k: usize) -> ModInt<M> {
            if n >= k {
                self.fact(n) * self.fact_inv(n - k) * self.fact_inv(k)
            } else {
                ModInt::new(0)
            }
        }
        pub fn perm(&self, n: usize, k: usize) -> ModInt<M> {
            if n >= k {
                self.fact(n) * self.fact_inv(n - k)
            } else {
                ModInt::new(0)
            }
        }
    }
}
pub mod mod_int {
    use std::{
        cmp,
        fmt::{self, Debug, Display},
        hash::Hash,
        iter::{Product, Sum},
        marker::PhantomData,
        mem,
        ops::*,
    };
    pub struct ModInt<M> {
        x: u32,
        marker: PhantomData<*const M>,
    }
    pub trait Modulo {
        fn modulo() -> u32;
    }
    impl<M> ModInt<M> {
        pub fn new(x: u32) -> Self {
            Self {
                x,
                marker: PhantomData,
            }
        }
        pub fn get(self) -> u32 {
            self.x
        }
    }
    impl<M: Modulo> ModInt<M> {
        pub fn modulo() -> u32 {
            M::modulo()
        }
        pub fn normalize(self) -> Self {
            Self::new(self.x % M::modulo())
        }
        pub fn inv(self) -> Self {
            assert_ne!(self.get(), 0);
            self.pow(M::modulo() - 2)
        }
        pub fn twice(self) -> Self {
            self + self
        }
        pub fn half(self) -> Self {
            if self.x & 1 == 0 {
                Self::new(self.x >> 1)
            } else {
                Self::new((self.x >> 1) + ((Self::modulo() + 1) >> 1))
            }
        }
    }
    impl<M> Clone for ModInt<M> {
        fn clone(&self) -> Self {
            Self::new(self.x)
        }
    }
    impl<M> Copy for ModInt<M> {}
    impl<M: Modulo> Neg for ModInt<M> {
        type Output = Self;
        fn neg(self) -> Self {
            Self::new(if self.x != 0 { M::modulo() - self.x } else { 0 })
        }
    }
    impl<M: Modulo> Neg for &ModInt<M> {
        type Output = ModInt<M>;
        fn neg(self) -> Self::Output {
            -(*self)
        }
    }
    impl<M: Modulo> Add for ModInt<M> {
        type Output = Self;
        fn add(self, rhs: Self) -> Self {
            let x = self.x + rhs.x;
            Self::new(if x < M::modulo() { x } else { x - M::modulo() })
        }
    }
    impl<M: Modulo> Sub for ModInt<M> {
        type Output = Self;
        fn sub(self, rhs: Self) -> Self {
            let x = if self.x >= rhs.x {
                self.x - rhs.x
            } else {
                M::modulo() + self.x - rhs.x
            };
            Self::new(x)
        }
    }
    impl<M: Modulo> Mul for ModInt<M> {
        type Output = Self;
        fn mul(self, rhs: Self) -> Self {
            let x = (self.x as u64 * rhs.x as u64) % M::modulo() as u64;
            Self::new(x as u32)
        }
    }
    impl<M: Modulo> Div for ModInt<M> {
        type Output = Self;
        #[allow(clippy::suspicious_arithmetic_impl)]
        fn div(self, rhs: Self) -> Self {
            self * rhs.inv()
        }
    }
    macro_rules! biops {
        ($ Op : ident , $ op : ident , $ OpAssign : ident , $ op_assign : ident) => {
            impl<M: Modulo> $Op<&Self> for ModInt<M> {
                type Output = Self;
                fn $op(self, rhs: &Self) -> Self {
                    self.$op(*rhs)
                }
            }
            impl<M: Modulo> $Op<ModInt<M>> for &ModInt<M> {
                type Output = ModInt<M>;
                fn $op(self, rhs: ModInt<M>) -> ModInt<M> {
                    (*self).$op(rhs)
                }
            }
            impl<M: Modulo> $Op for &ModInt<M> {
                type Output = ModInt<M>;
                fn $op(self, rhs: Self) -> ModInt<M> {
                    (*self).$op(*rhs)
                }
            }
            impl<M: Modulo> $OpAssign for ModInt<M> {
                fn $op_assign(&mut self, rhs: Self) {
                    *self = self.$op(rhs);
                }
            }
            impl<M: Modulo> $OpAssign<&Self> for ModInt<M> {
                fn $op_assign(&mut self, rhs: &Self) {
                    *self = self.$op(rhs);
                }
            }
        };
    }
    biops!(Add, add, AddAssign, add_assign);
    biops!(Sub, sub, SubAssign, sub_assign);
    biops!(Mul, mul, MulAssign, mul_assign);
    biops!(Div, div, DivAssign, div_assign);
    impl<M: Modulo> Sum for ModInt<M> {
        fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
            iter.fold(ModInt::new(0), |x, y| x + y)
        }
    }
    impl<M: Modulo> Product for ModInt<M> {
        fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
            iter.fold(ModInt::new(1), |x, y| x * y)
        }
    }
    macro_rules! fold {
        ($ Trait : ident , $ f : ident) => {
            impl<'a, M: Modulo + 'a> $Trait<&'a ModInt<M>> for ModInt<M> {
                fn $f<I: Iterator<Item = &'a ModInt<M>>>(iter: I) -> Self {
                    iter.copied().$f()
                }
            }
        };
    }
    fold!(Sum, sum);
    fold!(Product, product);
    pub trait Pow<Exp> {
        fn pow(self, exp: Exp) -> Self;
    }
    macro_rules! pow {
        ($ uty : ident , $ ity : ident) => {
            impl<M: Modulo> Pow<$uty> for ModInt<M> {
                fn pow(self, mut exp: $uty) -> Self {
                    if exp == 0 {
                        return ModInt::new(1);
                    }
                    let mut res = ModInt::new(1);
                    let mut base = self;
                    while exp > 1 {
                        if exp & 1 != 0 {
                            res *= base;
                        }
                        exp >>= 1;
                        base *= base;
                    }
                    base * res
                }
            }
            impl<M: Modulo> Pow<$ity> for ModInt<M> {
                fn pow(self, exp: $ity) -> Self {
                    if exp >= 0 {
                        self.pow(exp as $uty)
                    } else {
                        self.inv().pow(-exp as $uty)
                    }
                }
            }
        };
    }
    macro_rules ! impls { ($ m : ident , $ ($ uty : ident , $ ity : ident) ,*) => { $ ($ m ! ($ uty , $ ity) ;) * } ; }
    impls!(pow, usize, isize, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128);
    impl<M> Default for ModInt<M> {
        fn default() -> Self {
            Self::new(0)
        }
    }
    impl<M> PartialEq for ModInt<M> {
        fn eq(&self, other: &Self) -> bool {
            self.x == other.x
        }
    }
    impl<M> Eq for ModInt<M> {}
    impl<M> PartialOrd for ModInt<M> {
        fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
            self.x.partial_cmp(&other.x)
        }
    }
    impl<M> Ord for ModInt<M> {
        fn cmp(&self, other: &Self) -> cmp::Ordering {
            self.x.cmp(&other.x)
        }
    }
    impl<M> Hash for ModInt<M> {
        fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
            self.x.hash(state)
        }
    }
    macro_rules! from_uint {
        ($ ty : ident) => {
            impl<M: Modulo> From<$ty> for ModInt<M> {
                fn from(x: $ty) -> Self {
                    if mem::size_of::<$ty>() <= 4 {
                        if ($ty::max_value() as u32) < M::modulo() {
                            Self::new(x as u32)
                        } else {
                            Self::new(x as u32).normalize()
                        }
                    } else {
                        Self::new((x % M::modulo() as $ty) as u32)
                    }
                }
            }
        };
    }
    macro_rules ! impls { ($ m : ident , $ ($ ty : ident) ,*) => { $ ($ m ! ($ ty) ;) * } ; }
    impls!(from_uint, usize, u8, u16, u32, u64, u128);
    macro_rules! from_small_int {
        ($ ty : ident) => {
            impl<M: Modulo> From<$ty> for ModInt<M> {
                fn from(x: $ty) -> Self {
                    let mut x = x as i32;
                    if x >= 0 {
                        Self::from(x as u32)
                    } else {
                        while x < 0 {
                            x += M::modulo() as i32;
                        }
                        Self::new(x as u32)
                    }
                }
            }
        };
    }
    impls!(from_small_int, i8, i16, i32);
    impl<M> Display for ModInt<M> {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            Display::fmt(&self.x, f)
        }
    }
    impl<M> Debug for ModInt<M> {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            Debug::fmt(&self.x, f)
        }
    }
    #[macro_export]
    macro_rules! def_mint {
        ($ modulo : expr) => {
            #[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
            pub struct MintModulo;
            impl crate::mod_int::Modulo for MintModulo {
                fn modulo() -> u32 {
                    $modulo
                }
            }
            pub type Mint = crate::mod_int::ModInt<MintModulo>;
            pub fn mint<T: Into<Mint>>(x: T) -> Mint {
                x.into()
            }
        };
    }
}
pub mod input {
    use std::{
        io::{self, prelude::*},
        marker::PhantomData,
        mem,
    };
    pub trait Input {
        fn bytes(&mut self) -> &[u8];
        fn bytes_vec(&mut self) -> Vec<u8> {
            self.bytes().to_vec()
        }
        fn str(&mut self) -> &str {
            std::str::from_utf8(self.bytes()).unwrap()
        }
        fn parse<T: Parse>(&mut self) -> T {
            self.parse_with(DefaultParser)
        }
        fn parse_with<T>(&mut self, mut parser: impl Parser<T>) -> T {
            parser.parse(self)
        }
        fn seq<T: Parse>(&mut self) -> Seq<T, Self, DefaultParser> {
            self.seq_with(DefaultParser)
        }
        fn seq_with<T, P: Parser<T>>(&mut self, parser: P) -> Seq<T, Self, P> {
            Seq {
                input: self,
                parser,
                marker: PhantomData,
            }
        }
    }
    impl<T: Input> Input for &mut T {
        fn bytes(&mut self) -> &[u8] {
            (**self).bytes()
        }
    }
    pub trait Parser<T> {
        fn parse<I: Input + ?Sized>(&mut self, s: &mut I) -> T;
    }
    impl<T, P: Parser<T>> Parser<T> for &mut P {
        fn parse<I: Input + ?Sized>(&mut self, s: &mut I) -> T {
            (**self).parse(s)
        }
    }
    pub trait Parse {
        fn parse<I: Input + ?Sized>(s: &mut I) -> Self;
    }
    pub struct DefaultParser;
    impl<T: Parse> Parser<T> for DefaultParser {
        fn parse<I: Input + ?Sized>(&mut self, s: &mut I) -> T {
            T::parse(s)
        }
    }
    pub struct Seq<'a, T, I: ?Sized, P> {
        input: &'a mut I,
        parser: P,
        marker: PhantomData<*const T>,
    }
    impl<'a, T, I: Input, P: Parser<T>> Iterator for Seq<'a, T, I, P> {
        type Item = T;
        #[inline]
        fn next(&mut self) -> Option<Self::Item> {
            Some(self.input.parse_with(&mut self.parser))
        }
        fn size_hint(&self) -> (usize, Option<usize>) {
            (!0, None)
        }
    }
    impl Parse for char {
        #[inline]
        fn parse<I: Input + ?Sized>(s: &mut I) -> Self {
            let s = s.bytes();
            debug_assert_eq!(s.len(), 1);
            *s.first().expect("zero length") as char
        }
    }
    macro_rules ! tuple { ($ ($ T : ident) ,*) => { impl <$ ($ T : Parse) ,*> Parse for ($ ($ T ,) *) { # [inline] # [allow (unused_variables)] # [allow (clippy :: unused_unit)] fn parse < I : Input + ? Sized > (s : & mut I) -> Self { ($ ($ T :: parse (s) ,) *) } } } ; }
    tuple!();
    tuple!(A);
    tuple!(A, B);
    tuple!(A, B, C);
    tuple!(A, B, C, D);
    tuple!(A, B, C, D, E);
    tuple!(A, B, C, D, E, F);
    tuple!(A, B, C, D, E, F, G);
    #[cfg(feature = "newer")]
    impl<T: Parse, const N: usize> Parse for [T; N] {
        fn parse<I: Input + ?Sized>(s: &mut I) -> Self {
            use std::{mem::MaybeUninit, ptr};
            struct Guard<T, const N: usize> {
                arr: [MaybeUninit<T>; N],
                i: usize,
            }
            impl<T, const N: usize> Drop for Guard<T, N> {
                fn drop(&mut self) {
                    unsafe {
                        ptr::drop_in_place(&mut self.arr[..self.i] as *mut _ as *mut [T]);
                    }
                }
            }
            let mut g = Guard::<T, N> {
                arr: unsafe { MaybeUninit::uninit().assume_init() },
                i: 0,
            };
            while g.i < N {
                g.arr[g.i] = MaybeUninit::new(s.parse());
                g.i += 1;
            }
            unsafe { mem::transmute_copy(&g.arr) }
        }
    }
    macro_rules! uint {
        ($ ty : ty) => {
            impl Parse for $ty {
                #[inline]
                fn parse<I: Input + ?Sized>(s: &mut I) -> Self {
                    let s = s.bytes();
                    s.iter().fold(0, |x, d| 10 * x + (0xf & d) as $ty)
                }
            }
        };
    }
    macro_rules! int {
        ($ ty : ty) => {
            impl Parse for $ty {
                #[inline]
                fn parse<I: Input + ?Sized>(s: &mut I) -> Self {
                    let f = |s: &[u8]| {
                        s.iter()
                            .fold(0 as $ty, |x, d| (10 * x).wrapping_add((0xf & d) as $ty))
                    };
                    let s = s.bytes();
                    if let [b'-', s @ ..] = s {
                        f(s).wrapping_neg()
                    } else {
                        f(s)
                    }
                }
            }
        };
    }
    macro_rules! float {
        ($ ty : ty) => {
            impl Parse for $ty {
                fn parse<I: Input + ?Sized>(s: &mut I) -> Self {
                    const POW: [$ty; 18] = [
                        1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13,
                        1e14, 1e15, 1e16, 1e17,
                    ];
                    let s = s.bytes();
                    let (minus, s) = if let Some((b'-', s)) = s.split_first() {
                        (true, s)
                    } else {
                        (false, s)
                    };
                    let (int, fract) = if let Some(p) = s.iter().position(|c| *c == b'.') {
                        (&s[..p], &s[p + 1..])
                    } else {
                        (s, &[][..])
                    };
                    let x = int
                        .iter()
                        .chain(fract)
                        .fold(0u64, |x, d| 10 * x + (0xf & *d) as u64);
                    let x = x as $ty;
                    let x = if minus { -x } else { x };
                    let exp = fract.len();
                    if exp == 0 {
                        x
                    } else if let Some(pow) = POW.get(exp) {
                        x / pow
                    } else {
                        x / (10.0 as $ty).powi(exp as i32)
                    }
                }
            }
        };
    }
    macro_rules! from_bytes {
        ($ ty : ty) => {
            impl Parse for $ty {
                #[inline]
                fn parse<I: Input + ?Sized>(s: &mut I) -> Self {
                    s.bytes().into()
                }
            }
        };
    }
    macro_rules! from_str {
        ($ ty : ty) => {
            impl Parse for $ty {
                #[inline]
                fn parse<I: Input + ?Sized>(s: &mut I) -> Self {
                    s.str().into()
                }
            }
        };
    }
    macro_rules ! impls { ($ m : ident , $ ($ ty : ty) ,*) => { $ ($ m ! ($ ty) ;) * } ; }
    impls!(uint, usize, u8, u16, u32, u64, u128);
    impls!(int, isize, i8, i16, i32, i64, i128);
    impls!(float, f32, f64);
    impls!(from_bytes, Vec<u8>, Box<[u8]>);
    impls!(from_str, String);
    #[derive(Clone)]
    pub struct SplitWs<T> {
        src: T,
        buf: Vec<u8>,
        pos: usize,
        len: usize,
    }
    const BUF_SIZE: usize = 1 << 26;
    impl<T: Read> SplitWs<T> {
        pub fn new(src: T) -> Self {
            Self {
                src,
                buf: vec![0; BUF_SIZE],
                pos: 0,
                len: 0,
            }
        }
        #[inline(always)]
        fn peek(&self) -> &[u8] {
            unsafe { self.buf.get_unchecked(self.pos..self.len) }
        }
        #[inline(always)]
        fn consume(&mut self, n: usize) -> &[u8] {
            let pos = self.pos;
            self.pos += n;
            unsafe { self.buf.get_unchecked(pos..self.pos) }
        }
        fn read(&mut self) -> usize {
            self.buf.copy_within(self.pos..self.len, 0);
            self.len -= self.pos;
            self.pos = 0;
            if self.len == self.buf.len() {
                self.buf.resize(2 * self.buf.len(), 0);
            }
            loop {
                match self.src.read(&mut self.buf[self.len..]) {
                    Ok(n) => {
                        self.len += n;
                        return n;
                    }
                    Err(e) if e.kind() == io::ErrorKind::WouldBlock => {}
                    Err(e) => panic!("io error: {:?}", e),
                }
            }
        }
    }
    impl<T: Read> Input for SplitWs<T> {
        #[inline]
        fn bytes(&mut self) -> &[u8] {
            loop {
                if let Some(del) = self.peek().iter().position(|c| c.is_ascii_whitespace()) {
                    if del > 0 {
                        let s = self.consume(del + 1);
                        return s.split_last().unwrap().1;
                    } else {
                        self.consume(1);
                    }
                } else if self.read() == 0 {
                    return self.consume(self.len - self.pos);
                }
            }
        }
    }
}
pub mod macros {
    #[macro_export]
    macro_rules ! w { ($ ($ arg : tt) *) => { write ! ($ ($ arg) *) . unwrap () ; } }
    #[macro_export]
    macro_rules ! wln { ($ dst : expr $ (, $ ($ arg : tt) *) ?) => { { writeln ! ($ dst $ (, $ ($ arg) *) ?) . unwrap () ; # [cfg (debug_assertions)] $ dst . flush () . unwrap () ; } } }
    #[macro_export]
    macro_rules! w_iter {
        ($ dst : expr , $ fmt : expr , $ iter : expr , $ delim : expr) => {{
            let mut first = true;
            for elem in $iter {
                if first {
                    w!($dst, $fmt, elem);
                    first = false;
                } else {
                    w!($dst, concat!($delim, $fmt), elem);
                }
            }
        }};
        ($ dst : expr , $ fmt : expr , $ iter : expr) => {
            w_iter!($dst, $fmt, $iter, " ")
        };
    }
    #[macro_export]
    macro_rules ! w_iter_ln { ($ dst : expr , $ ($ t : tt) *) => { { w_iter ! ($ dst , $ ($ t) *) ; wln ! ($ dst) ; } } }
    #[macro_export]
    macro_rules ! e { ($ ($ t : tt) *) => { # [cfg (debug_assertions)] eprint ! ($ ($ t) *) } }
    #[macro_export]
    macro_rules ! eln { ($ ($ t : tt) *) => { # [cfg (debug_assertions)] eprintln ! ($ ($ t) *) } }
    #[macro_export]
    #[doc(hidden)]
    macro_rules ! __tstr { ($ h : expr $ (, $ t : expr) +) => { concat ! (__tstr ! ($ ($ t) ,+) , ", " , __tstr ! (@)) } ; ($ h : expr) => { concat ! (__tstr ! () , " " , __tstr ! (@)) } ; () => { "\x1B[94m[{}:{}]\x1B[0m" } ; (@) => { "\x1B[1;92m{}\x1B[0m = {:?}" } }
    #[macro_export]
    macro_rules ! d { ($ ($ a : expr) ,*) => { if std :: env :: var ("ND") . map (| v | & v == "0") . unwrap_or (true) { eln ! (__tstr ! ($ ($ a) ,*) , file ! () , line ! () , $ (stringify ! ($ a) , $ a) ,*) ; } } ; }
}