Problem:
Score : 800 points

Problem Statement

Let’s take a prime P = 200\,003.
You are given N integers A_1, A_2, \ldots, A_N.
Find the sum of ((A_i \cdot A_j) \bmod P) over all N \cdot (N-1) / 2 unordered pairs of elements (i < j).

Please note that the sum isn't computed modulo P.

Constraints

2 \leq N \leq 200\,000

0 \leq A_i < P = 200\,003

All values in input are integers.

Input

Input is given from Standard Input in the following format.

N
A_1 A_2 \cdots A_N

Output

Print one integer — the sum over ((A_i \cdot A_j) \bmod P).

Sample Input 1

4
2019 0 2020 200002

Sample Output 1

474287

The non-zero products are:

2019 \cdot 2020 \bmod P = 78320

2019 \cdot 200002 \bmod P = 197984

2020 \cdot 200002 \bmod P = 197983

So the answer is 0 + 78320 + 197984 + 0 + 0 + 197983 = 474287.

Sample Input 2

5
1 1 2 2 100000

Sample Output 2

600013

Solution in Rust (1.42.0) (judge verdict: Accepted)

use std::cmp::*;
use input_mcr::*;

use complex::*;
use fft::*;
use discrete_log::*;

fn main() {
    input! {
        n: usize,
        xs: [i64; n],
    }
    let p = 200_003i64;

    let log_table = gen_discrate_log_table(p as usize, 2).unwrap();
    let pow_table = gen_discrate_pow_table(p as usize, 2);
    for i in 1..(p-2) as usize {
        assert!(pow_table[log_table[i]] == i);
    }
    let mut ys = vec![Complex::default(); 524288];
    for &x in &xs {
        if x != 0 {
            // eprintln!("log{} = {:?}", x, log_table[x as usize]);
            ys[log_table[x as usize]].real += 1.0;
        }
    }
    let zs = fft_conv(&ys, &ys);
    let mut res = 0i64;
    for &x in &xs {
        res -= (x * x) % p;
    }
    for i in 0..zs.len() {
        if zs[i].real > 0.1 {
            // eprintln!("i = {}, log_i = {}, v = {}", i, pow_table[i%(p-1) as usize], zs[i].real);
            res += pow_table[i%(p-1) as usize] as i64 * (zs[i].real + 0.5) as i64;
        }
    }
    let res = res / 2;
    println!("{}", res);
}
pub mod input_mcr {
    // ref: tanakh <https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8>
    #[macro_export(local_inner_macros)]
    macro_rules! input {
        (source = $s:expr, $($r:tt)*) => {
            let mut parser = Parser::from_str($s);
            input_inner!{parser, $($r)*}
        };
        (parser = $parser:ident, $($r:tt)*) => {
            input_inner!{$parser, $($r)*}
        };
        (new_stdin_parser = $parser:ident, $($r:tt)*) => {
            let stdin = std::io::stdin();
            let reader = std::io::BufReader::new(stdin.lock());
            let mut $parser = Parser::new(reader);
            input_inner!{$parser, $($r)*}
        };
        ($($r:tt)*) => {
            input!{new_stdin_parser = parser, $($r)*}
        };
    }
    
    #[macro_export(local_inner_macros)]
    macro_rules! input_inner {
        ($parser:ident) => {};
        ($parser:ident, ) => {};
        ($parser:ident, $var:ident : $t:tt $($r:tt)*) => {
            let $var = read_value!($parser, $t);
            input_inner!{$parser $($r)*}
        };
    }
    
    #[macro_export(local_inner_macros)]
    macro_rules! read_value {
        ($parser:ident, ( $($t:tt),* )) => {
            ( $(read_value!($parser, $t)),* )
        };
        ($parser:ident, [ $t:tt ; $len:expr ]) => {
            (0..$len).map(|_| read_value!($parser, $t)).collect::<Vec<_>>()
        };
        ($parser:ident, chars) => {
            read_value!($parser, String).chars().collect::<Vec<char>>()
        };
        ($parser:ident, char_) => {
            read_value!($parser, String).chars().collect::<Vec<char>>()[0]
        };
        ($parser:ident, usize1) => {
            read_value!($parser, usize) - 1
        };
        ($parser:ident, line) => {
            $parser.next_line()
        };
        ($parser:ident, line_) => {
            $parser.next_line().chars().collect::<Vec<char>>()
        };
        ($parser:ident, $t:ty) => {
            $parser.next::<$t>().expect("Parse error")
        };
    }
    
    use std::io;
    use std::io::BufRead;
    use std::str;
    use std::collections::VecDeque;
    
    pub struct Parser<R> {
        pub reader: R,
        buf: VecDeque<u8>,
        parse_buf: Vec<u8>,
    }
    
    impl Parser<io::Empty> {
        pub fn from_str(s: &str) -> Parser<io::Empty> {
            Parser {
                reader: io::empty(),
                buf: VecDeque::from(s.as_bytes().to_vec()),
                parse_buf: vec![],
            }
        }
    }
    
    impl<R: BufRead> Parser<R> {
        pub fn new(reader: R) -> Parser<R> {
            Parser {
                reader: reader,
                buf: VecDeque::new(),
                parse_buf: vec![],
            }
        }
        pub fn update_buf(&mut self) {
            loop {
                let (len, complete) = {
                    let buf2 = self.reader.fill_buf().unwrap();
                    self.buf.extend(buf2.iter());
                    let len = buf2.len();
                    (len, buf2.last() < Some(&0x20))
                };
                self.reader.consume(len);
                if complete {
                    break;
                }
            }
        }
        pub fn next<T: str::FromStr>(&mut self) -> Result<T, T::Err> {
            loop {
                while let Some(c) = self.buf.pop_front() {
                    if c > 0x20 {
                        self.buf.push_front(c);
                        break;
                    }
                }
                self.parse_buf.clear();
                while let Some(c) = self.buf.pop_front() {
                    if c <= 0x20 {
                        self.buf.push_front(c);
                        break;
                    } else {
                        self.parse_buf.push(c);
                    }
                }
                if self.parse_buf.is_empty() {
                    self.update_buf();
                } else {
                    return unsafe { str::from_utf8_unchecked(&self.parse_buf) }.parse::<T>();
                }
            }
        }
        pub fn next_line(&mut self) -> String {
            loop {
                while let Some(c) = self.buf.pop_front() {
                    if c >= 0x20 {
                        self.buf.push_front(c);
                        break;
                    }
                }
                self.parse_buf.clear();
                while let Some(c) = self.buf.pop_front() {
                    if c < 0x20 {
                        self.buf.push_front(c);
                        break;
                    } else {
                        self.parse_buf.push(c);
                    }
                }
                if self.parse_buf.is_empty() {
                    self.update_buf();
                } else {
                    return unsafe { str::from_utf8_unchecked(&self.parse_buf) }.to_string();
                }
            }
        }
    }
}
pub mod complex {
    use std::ops::*;
    
    #[derive(Default, Debug, Clone, Copy, PartialEq)]
    pub struct Complex {
        pub real: f64,
        pub imag: f64,
    }
    
    impl Complex {
        pub fn new(real: f64, imag: f64) -> Complex {
            Complex {
                real,
                imag,
            }
        }
        pub fn polar(r: f64, theta: f64) -> Complex {
            Complex {
                real: r * theta.cos(),
                imag: r * theta.sin(),
            }
        }
    }
    
    impl Add for Complex {
        type Output = Self;
        fn add(self, rhs: Self) -> Self {
            Complex {
                real: self.real + rhs.real,
                imag: self.imag + rhs.imag,
            }
        }
    }
    
    impl Sub for Complex {
        type Output = Self;
        fn sub(self, rhs: Self) -> Self {
            Complex {
                real: self.real - rhs.real,
                imag: self.imag - rhs.imag,
            }
        }
    }
    
    impl Mul for Complex {
        type Output = Self;
        fn mul(self, rhs: Self) -> Self {
            Complex {
                real: self.real * rhs.real - self.imag * rhs.imag,
                imag: self.imag * rhs.real + self.real * rhs.imag,
            }
        }
    }
    
    impl MulAssign for Complex {
        fn mul_assign(&mut self, rhs: Self) {
            *self = *self * rhs;
        }
    }
    
    
    impl Div for Complex {
        type Output = Self;
        fn div(self, rhs: Self) -> Self {
            let t = rhs.real * rhs.real + rhs.imag * rhs.imag;
            Complex {
                real: (self.real * rhs.real + self.imag * rhs.imag) / t,
                imag: (self.imag * rhs.real - self.real * rhs.imag) / t,
            }
        }
    }
    
    impl Div<f64> for Complex {
        type Output = Self;
        fn div(self, rhs: f64) -> Self {
            Complex {
                real: self.real / rhs,
                imag: self.imag / rhs,
            }
        }
    }
    
    impl DivAssign<f64> for Complex {
        fn div_assign(&mut self, rhs: f64) {
            self.real /= rhs;
            self.imag /= rhs;
        }
    }
    
}
pub mod fft {
    use crate::complex::*;
    
    pub fn fft(xs: &mut Vec<Complex>, inv: bool) {
        let n = xs.len();
        assert!(n.count_ones() == 1);
        let h = n.trailing_zeros();
        for i in 0..n {
            let mut j = 0;
            for k in 0..h {
                j |= ((i >> k) & 1) << (h - 1 - k);
            }
            if i < j {
                xs.swap(i, j);
            }
        }
    
        for b in (0..h).map(|x| 1<<x) {
            for j in 0..b {
                let theta = 
                    if inv {
                        2.0 * std::f64::consts::PI / (2.0 * b as f64) * j as f64
                    } else {
                        -2.0 * std::f64::consts::PI / (2.0 * b as f64) * j as f64
                    };
                let w = Complex::polar(1.0, theta);
                for k in (0..n).step_by(2*b) {
                    let s = xs[j + k];
                    let t = xs[j + k + b] * w;
                    xs[j + k] = s + t;
                    xs[j + k + b] = s - t;
                }
            }
        }
    
        if inv {
            for x in xs.iter_mut() {
                *x /= n as f64;
            }
        }
    }
    
    pub fn fft_conv(xs: &Vec<Complex>, ys: &Vec<Complex>) -> Vec<Complex> {
        assert_eq!(xs.len(), ys.len());
        let mut xs = xs.clone();
        let mut ys = ys.clone();
        fft(&mut xs, false);
        fft(&mut ys, false);
        for i in 0..xs.len() {
            xs[i] *= ys[i];
        } 
        fft(&mut xs, true);   
        xs
    }
}
pub mod discrete_log {
    pub fn gen_discrate_log_table(n: usize, w: usize) -> Option<Vec<usize>> {
        let mut res = vec![0; n];
        let mut t = 1;
        for i in 0..n-1 {
            if res[t] != 0 {
                return None;
            }
            res[t] = i;
            t = (t * w) % n;
        }
        Some(res)
    }
    
    pub fn gen_discrate_pow_table(n: usize, w: usize) -> Vec<usize> {
        let mut res = vec![0; n];
        let mut t = 1;
        for i in 0..n {
            res[i] = t;
            t = (t * w) % n;
        }
        res
    }
}