use math::floor_sum;
use std::io::*;
use utils::*;

pub fn main() {
    let i = stdin();
    let mut o = Vec::new();
    run(i.lock(), &mut o).unwrap();
    stdout().write_all(&o).unwrap();
}

pub fn run(i: impl BufRead, o: &mut impl Write) -> std::io::Result<()> {
    let mut i = CpReader::new(i);
    let t = i.read::<usize>();
    for (n, m, a, b) in i.read_iter::<(i64, i64, i64, i64)>(t) {
        writeln!(o, "{}", floor_sum(n, m, a, b))?;
    }
    Ok(())
}

pub mod utils {
    use super::*;

    pub struct CpReader<R: BufRead> {
        r: R,
        b: Vec<u8>,
    }
    impl<R: BufRead> CpReader<R> {
        pub fn new(r: R) -> Self {
            CpReader {
                r: r,
                b: Vec::new(),
            }
        }
        pub fn read_word(&mut self) -> &[u8] {
            self.b.clear();
            loop {
                let b = self.r.fill_buf().unwrap();
                assert!(!b.is_empty());
                if let Some(p) = b.iter().position(|&x| x == b' ' || x == b'\n') {
                    self.b.extend_from_slice(&b[..p]);
                    self.r.consume(p + 1);
                    return &self.b;
                }
                self.b.extend_from_slice(b);
                let b_len = b.len();
                self.r.consume(b_len);
            }
        }
        pub fn read_word_str(&mut self) -> &str {
            unsafe { std::str::from_utf8_unchecked(self.read_word()) }
        }

        pub fn read_line(&mut self) -> &[u8] {
            self.b.clear();
            self.r.read_until(b'\n', &mut self.b).unwrap();
            if self.b.last() == Some(&b'\n') {
                &self.b[..self.b.len() - 1]
            } else {
                &self.b
            }
        }
        pub fn read_line_str(&mut self) -> &str {
            unsafe { std::str::from_utf8_unchecked(self.read_line()) }
        }

        pub fn read<T: CpIn>(&mut self) -> T {
            T::read_from(self)
        }

        pub fn read_vec<T: CpIn>(&mut self, n: usize) -> Vec<T> {
            (0..n).map(|_| self.read()).collect()
        }
        pub fn read_iter<'a, T: CpIn>(&'a mut self, n: usize) -> CpIter<'a, R, T> {
            CpIter {
                r: self,
                n: n,
                _pd: Default::default(),
            }
        }
    }
    pub struct CpIter<'a, R: BufRead + 'a, T> {
        r: &'a mut CpReader<R>,
        n: usize,
        _pd: std::marker::PhantomData<fn() -> T>,
    }
    impl<'a, R: BufRead, T: CpIn> Iterator for CpIter<'a, R, T> {
        type Item = T;
        fn next(&mut self) -> Option<T> {
            if self.n == 0 {
                None
            } else {
                self.n -= 1;
                Some(self.r.read())
            }
        }
        fn size_hint(&self) -> (usize, Option<usize>) {
            (self.n, Some(self.n))
        }
    }
    impl<'a, R: BufRead, T: CpIn> ExactSizeIterator for CpIter<'a, R, T> {}

    pub trait CpIn {
        fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self;
    }

    impl CpIn for u64 {
        fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
            read_u64_fast(&mut r.r)
        }
    }
    impl CpIn for i64 {
        fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
            read_i64_fast(&mut r.r)
        }
    }
    impl CpIn for char {
        fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
            let b = r.r.fill_buf().unwrap()[0] as char;
            r.r.consume(1);
            let s = r.r.fill_buf().unwrap()[0];
            assert!(s == b' ' || s == b'\n');
            r.r.consume(1);
            b
        }
    }

    macro_rules! cpin_tuple {
        ($($t:ident),*) => {
            impl<$($t: CpIn),*> CpIn for ($($t),*) {
                fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
                    ($($t::read_from(r)),*)
                }
            }
        };
    }

    macro_rules! cpin_cast {
        ($t_self:ty, $t_read:ty) => {
            impl CpIn for $t_self {
                fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
                    <$t_read>::read_from(r) as $t_self
                }
            }
        };
    }
    macro_rules! cpin_parse {
        ($t:ty) => {
            impl CpIn for $t {
                fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
                    r.read_word_str().parse().unwrap()
                }
            }
        };
    }
    cpin_cast!(usize, u64);
    cpin_cast!(u32, u64);
    cpin_cast!(u16, u64);
    cpin_cast!(i32, i64);
    cpin_cast!(i16, i64);
    cpin_cast!(i8, i64);

    cpin_parse!(f64);

    cpin_tuple!(T1, T2);
    cpin_tuple!(T1, T2, T3);
    cpin_tuple!(T1, T2, T3, T4);
    cpin_tuple!(T1, T2, T3, T4, T5);

    fn read_u64_fast<R: BufRead>(r: &mut R) -> u64 {
        let mut value = 0;
        loop {
            let buf = r.fill_buf().unwrap();
            assert!(!buf.is_empty());
            let mut idx = 0;
            while let Some(&c) = buf.get(idx) {
                if b'0' <= c && c <= b'9' {
                    value = value * 10 + (c - b'0') as u64;
                    idx += 1;
                } else {
                    r.consume(idx + 1);
                    return value;
                }
            }
            r.consume(idx);
        }
    }
    fn read_i64_fast<R: BufRead>(r: &mut R) -> i64 {
        let sign = match r.fill_buf().unwrap()[0] {
            b'+' => {
                r.consume(1);
                1
            }
            b'-' => {
                r.consume(1);
                -1
            }
            _ => 1,
        };
        read_u64_fast(r) as i64 * sign
    }
}

mod internal_math {
    #![allow(dead_code)]

    use std::mem::swap;

    pub fn safe_mod(mut x: i64, m: i64) -> i64 {
        x %= m;
        if x < 0 {
            x += m;
        }
        x
    }

    pub struct Barrett {
        m: u32,
        im: u64,
    }
    impl Barrett {
        pub fn new(m: u32) -> Self {
            Self {
                m,
                im: (-1i64 as u64) / (m as u64) + 1,
            }
        }
        pub fn umod(&self) -> u32 {
            self.m
        }

        pub fn mul(&self, a: u32, b: u32) -> u32 {
            let z = a as u64 * b as u64;
            let x = (((z as u128) * (self.im as u128)) >> 64) as u64;
            let mut v = (z - x * self.m as u64) as u32;
            if self.m < v {
                v += self.m;
            }
            v
        }
    }

    pub fn pow_mod(x: i64, mut n: i64, m: i32) -> i64 {
        if m == 1 {
            return 0;
        }
        let m_u32 = m as u32;
        let mut r = 1u64;
        let mut y = safe_mod(x, m as i64) as u64;
        while n != 0 {
            if n & 1 != 0 {
                r = (r * y) % (m_u32 as u64);
            }
            y = (y * y) % (m_u32 as u64);
            n >>= 1;
        }
        r as i64
    }
    pub fn is_prime(n: i32) -> bool {
        if n <= 1 {
            return false;
        }
        if n == 2 || n == 7 || n == 61 {
            return true;
        }
        if n % 2 == 0 {
            return false;
        }
        let n_i64 = n as i64;
        let mut d: i64 = n_i64 - 1 as i64;
        while d % 2 == 0 {
            d /= 2;
        }
        for &a in &[2i64, 7, 61] {
            let mut t: i64 = d;
            let mut y: i64 = pow_mod(a, t, n);
            while t != n_i64 - 1 && y != 1 && y != n_i64 - 1 {
                y = y * y % n_i64;
                t <<= 1;
            }
            if y != n_i64 - 1 && t % 2 == 0 {
                return false;
            }
        }
        true
    }

    pub fn inv_gcd(mut a: i64, b: i64) -> (i64, i64) {
        a = safe_mod(a, b);
        if a == 0 {
            return (b, 0);
        }
        let mut s = b;
        let mut t = a;
        let mut m0 = 0;
        let mut m1 = 1;

        while t != 0 {
            let u = s / t;
            s -= t * u;
            m0 -= m1 * u;

            swap(&mut s, &mut t);
            swap(&mut m0, &mut m1);
        }
        if m0 < 0 {
            m0 += b / s;
        }
        (s, m0)
    }

    pub fn primitive_root_constexpr(m: i32) -> i32 {
        match m {
            2 => return 1,
            167772161 => return 3,
            469762049 => return 3,
            754974721 => return 11,
            998244353 => return 3,
            _ => {}
        }
        let mut divs = [0; 20];
        divs[0] = 2;
        let mut cnt = 1;
        let mut x = (m - 1) / 2;
        while x % 2 == 0 {
            x /= 2;
        }
        let mut i = 3;
        while (i as i64) * (i as i64) <= x as i64 {
            if x % i == 0 {
                divs[cnt] = i;
                cnt += 1;
                while x % i == 0 {
                    x /= i;
                }
            }

            i += 2;
        }
        if x > 1 {
            divs[cnt] = x;
            cnt += 1;
        }
        for g in 2.. {
            let mut ok = true;
            for i in 0..cnt {
                if pow_mod(g, ((m - 1) / divs[i]) as i64, m) == 1 {
                    ok = false;
                    break;
                }
            }
            if ok {
                return g as i32;
            }
        }
        unreachable!()
    }
}

mod math {
    #![allow(dead_code)]

    use crate::internal_math::*;
    use std::mem::swap;
    pub fn pow_mod(x: i64, mut n: u64, m: i32) -> i64 {
        debug_assert!(1 <= m);
        if m == 1 {
            return 0;
        }
        let bt = Barrett::new(m as u32);
        let mut r = 1;
        let mut y = safe_mod(x, m as i64) as u32;
        while n != 0 {
            if n & 1 != 0 {
                r = bt.mul(r, y);
            }
            y = bt.mul(y, y);
            n >>= 1;
        }
        r as i64
    }

    pub fn inv_mod(x: i64, m: i64) -> i64 {
        debug_assert!(1 <= m);
        let z = inv_gcd(x, m);
        debug_assert!(z.0 == 1);
        z.1
    }

    pub fn crt(r: &[i64], m: &[i64]) -> (i64, i64) {
        debug_assert_eq!(r.len(), m.len());
        let n = r.len();

        let mut r0 = 0;
        let mut m0 = 1;
        for i in 0..n {
            debug_assert!(1 <= m[i]);
            let mut r1 = safe_mod(r[i], m[i]);
            let mut m1 = m[i];
            if m0 < m1 {
                swap(&mut r0, &mut r1);
                swap(&mut m0, &mut m1);
            }
            if m0 % m1 == 0 {
                if r0 % m1 != r1 {
                    return (0, 0);
                }
                continue;
            }
            let (g, im) = inv_gcd(m0, m1);
            let u1 = m1 / g;
            if ((r1 - r0) % g) != 0 {
                return (0, 0);
            }
            let x = (r1 - r0) / g % u1 * im % u1;
            r0 += x * m0;
            m0 *= u1;
            if r0 < 0 {
                r0 += m0;
            }
        }
        (r0, m0)
    }

    pub fn floor_sum(n: i64, m: i64, mut a: i64, mut b: i64) -> i64 {
        let mut ans = 0;
        if a >= m {
            ans += (n - 1) * n * (a / m) / 2;
            a %= m;
        }
        if b >= m {
            ans += n * (b / m);
            b %= m;
        }

        let y_max = (a * n + b) / m;
        let x_max = y_max * m - b;
        if y_max == 0 {
            return ans;
        }
        ans += (n - (x_max + a - 1) / a) * y_max;
        ans += floor_sum(y_max, a, m, (a - x_max % a) % a);
        return ans;
    }
}


Measured memory_bytes: 3112