QOJ.ac

QOJ

IDSubmission IDProblemHackerOwnerResultSubmit timeJudge time
#463#254363#7749. A Simple MST Problemsansenucup-team635Success!2023-11-22 20:09:082023-11-22 20:09:09

Details

Extra Test:

Time Limit Exceeded

input:

8849
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2 113
2...

output:

223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
223
...

result:


IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#254363#7749. A Simple MST Problemucup-team635#TL 521ms38216kbRust9.8kb2023-11-18 11:36:442023-11-22 20:10:15

answer

use std::io::Write;

fn run() {
    input! {
        t: usize,
        ask: [(usize, usize); t],
    }
    let m = 1000000;
    let sieve = Sieve::new(m);
    let mut memo = InitArray::new(false, m + 1);
    let mut norm = vec![1; m + 1];
    let mut key = vec![0; m + 1];
    for (i, (norm, key)) in norm.iter_mut().zip(key.iter_mut()).enumerate().skip(1) {
        memo.init();
        let mut v = i;
        while let Some(p) = sieve.factor(v) {
            v /= p;
            if !memo[p] {
                *norm *= p;
                *key += 1;
                memo[p] = true;
            }
        }
    }
    let (key, norm) = (key, norm);
    let mut calc = |l: usize, r: usize| -> usize {
        if r - l <= 120 {
            let mut edge = vec![];
            for (i, a) in (l..=r).enumerate() {
                for (j, b) in (l..=r).enumerate().take(i) {
                    let w = key[a] + key[b] - key[binary_gcd(a, b)];
                    edge.push((w, i, j));
                }
            }
            let mut dsu = DSU::new(r - l + 1);
            edge.sort();
            let mut ans = 0;
            for (c, a, b) in edge {
                if dsu.unite(a, b).is_some() {
                    ans += c;
                }
            }
            return ans;
        }
        if l == 1 {
            return key[l..=r].iter().sum::<usize>();
        }
        let mut ord = (l..=r).collect::<Vec<_>>();
        ord.sort_by_key(|v| key[*v]);
        assert!(key[ord[0]] <= 1);
        memo.init();
        let mut ans = 0;
        let mut dp = vec![];
        for v in ord {
            ans += key[v];
            dp.clear();
            dp.push(1);
            let mut find = false;
            let mut x = norm[v];
            'outer: while let Some(p) = sieve.factor(x) {
                let len = dp.len();
                for i in 0..len {
                    let v = dp[i] * p;
                    if memo[v] {
                        find = true;
                        break 'outer;
                    }
                    dp.push(v);
                }
                x /= p;
            }
            if !find {
                ans += 1;
                memo[norm[v]] = true;
            }
        }
        ans - 2
    };
    let out = std::io::stdout();
    let mut out = std::io::BufWriter::new(out.lock());
    for (l, r) in ask {
        writeln!(out, "{}", calc(l, r)).ok();
    }
}

fn main() {
    run();
}

// ---------- begin input macro ----------
// reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
#[macro_export]
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_export]
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_export]
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 ----------
// ---------- begin enumerate prime ----------
fn enumerate_prime<F>(n: usize, mut f: F)
where
    F: FnMut(usize),
{
    assert!(1 <= n && n <= 5 * 10usize.pow(8));
    let batch = (n as f64).sqrt().ceil() as usize;
    let mut is_prime = vec![true; batch + 1];
    for i in (2..).take_while(|p| p * p <= batch) {
        if is_prime[i] {
            let mut j = i * i;
            while let Some(p) = is_prime.get_mut(j) {
                *p = false;
                j += i;
            }
        }
    }
    let mut prime = vec![];
    for (i, p) in is_prime.iter().enumerate().skip(2) {
        if *p && i <= n {
            f(i);
            prime.push(i);
        }
    }
    let mut l = batch + 1;
    while l <= n {
        let r = std::cmp::min(l + batch, n + 1);
        is_prime.clear();
        is_prime.resize(r - l, true);
        for &p in prime.iter() {
            let mut j = (l + p - 1) / p * p - l;
            while let Some(is_prime) = is_prime.get_mut(j) {
                *is_prime = false;
                j += p;
            }
        }
        for (i, _) in is_prime.iter().enumerate().filter(|p| *p.1) {
            f(i + l);
        }
        l += batch;
    }
}
// ---------- end enumerate prime ----------
//---------- begin union_find ----------
pub struct DSU {
    p: Vec<i32>,
}
impl DSU {
    pub fn new(n: usize) -> DSU {
        assert!(n < std::i32::MAX as usize);
        DSU { p: vec![-1; n] }
    }
    pub fn init(&mut self) {
        self.p.iter_mut().for_each(|p| *p = -1);
    }
    pub fn root(&self, mut x: usize) -> usize {
        assert!(x < self.p.len());
        while self.p[x] >= 0 {
            x = self.p[x] as usize;
        }
        x
    }
    pub fn same(&self, x: usize, y: usize) -> bool {
        assert!(x < self.p.len() && y < self.p.len());
        self.root(x) == self.root(y)
    }
    pub fn unite(&mut self, x: usize, y: usize) -> Option<(usize, usize)> {
        assert!(x < self.p.len() && y < self.p.len());
        let mut x = self.root(x);
        let mut y = self.root(y);
        if x == y {
            return None;
        }
        if self.p[x] > self.p[y] {
            std::mem::swap(&mut x, &mut y);
        }
        self.p[x] += self.p[y];
        self.p[y] = x as i32;
        Some((x, y))
    }
    pub fn parent(&self, x: usize) -> Option<usize> {
        assert!(x < self.p.len());
        let p = self.p[x];
        if p >= 0 {
            Some(p as usize)
        } else {
            None
        }
    }
    pub fn sum<F>(&self, mut x: usize, mut f: F) -> usize
    where
        F: FnMut(usize),
    {
        while let Some(p) = self.parent(x) {
            f(x);
            x = p;
        }
        x
    }
    pub fn size(&self, x: usize) -> usize {
        assert!(x < self.p.len());
        let r = self.root(x);
        (-self.p[r]) as usize
    }
}
//---------- end union_find ----------
// ---------- begin init array ----------
#[derive(Clone)]
pub struct InitArray<T> {
    data: Vec<T>,
    used: Vec<bool>,
    list: Vec<u32>,
    zero: T,
}

impl<T: Copy> InitArray<T> {
    pub fn new(zero: T, size: usize) -> Self {
        InitArray {
            data: vec![zero; size],
            used: vec![false; size],
            list: vec![],
            zero: zero,
        }
    }
    pub fn init(&mut self) {
        self.init_with(|_, _| ());
    }
    pub fn init_with<F>(&mut self, mut f: F)
    where
        F: FnMut(usize, T),
    {
        for x in self.list.drain(..) {
            let x = x as usize;
            self.used[x] = false;
            let v = std::mem::replace(&mut self.data[x], self.zero);
            f(x, v);
        }
    }
}

impl<T> std::ops::Index<usize> for InitArray<T> {
    type Output = T;
    fn index(&self, pos: usize) -> &Self::Output {
        &self.data[pos]
    }
}

impl<T> std::ops::IndexMut<usize> for InitArray<T> {
    fn index_mut(&mut self, pos: usize) -> &mut Self::Output {
        if !self.used[pos] {
            self.used[pos] = true;
            self.list.push(pos as u32);
        }
        &mut self.data[pos]
    }
}
// ---------- end init array ----------
// --------- end sieve ----------
pub struct Sieve {
    size: usize,
    factor: Vec<usize>,
}

impl Sieve {
    pub fn new(size: usize) -> Sieve {
        let mut factor = (0..(size + 1)).collect::<Vec<_>>();
        for i in (2..).take_while(|p| p * p <= size) {
            if i == factor[i] {
                for j in i..(size / i + 1) {
                    factor[j * i] = i;
                }
            }
        }
        Sieve {
            size: size,
            factor: factor,
        }
    }
    pub fn factor(&self, n: usize) -> Option<usize> {
        assert!(n <= self.size);
        if n == 1 {
            None
        } else {
            Some(self.factor[n])
        }
    }
    pub fn factorize(&self, mut n: usize, res: &mut Vec<usize>) {
        assert!(n <= self.size);
        res.clear();
        res.push(1);
        while let Some(p) = self.factor(n) {
            let len = res.len();
            while n % p == 0 {
                n /= p;
                for _ in 0..len {
                    let v = res[res.len() - len] * p;
                    res.push(v);
                }
            }
        }
    }
}
// --------- end sieve ----------
// ---------- begin binary_gcd ----------
pub fn binary_gcd(a: usize, b: usize) -> usize {
    if a == 0 || b == 0 {
        return a + b;
    }
    let x = a.trailing_zeros();
    let y = b.trailing_zeros();
    let mut a = a >> x;
    let mut b = b >> y;
    while a != b {
        let x = (a ^ b).trailing_zeros();
        if a < b {
            std::mem::swap(&mut a, &mut b);
        }
        a = (a - b) >> x;
    }
    a << x.min(y)
}
// ---------- end binary_gcd ----------