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::*;

#[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(),
        }
    }
}

use std::ops::*;

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 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;
        }
    }
}

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
}

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)
}

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
}

fn main3() {
    input! {
        n: usize,
        ws: [(i64,i64); n],
    }
    let m = (n+2).next_power_of_two() * 2;
    let mut xs = vec![Complex::default(); m];
    let mut ys = vec![Complex::default(); m];
    for (i, &(x,y)) in ws.iter().enumerate() {
        xs[i+1].real += x as f64;
        ys[i+1].real += y as f64;
    }
    let zs = fft_conv(&xs, &ys);
    for i in 1..2*n+1 {
        print!("{}\n", (zs[i].real + 0.5) as i64);
    }
    println!();
}

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);
}

fn modpow(x: i64, n: i64, m: i64) -> i64 {
    if n == 0 {
        return 1;
    }
    let t = modpow(x, n/2, m);
    if n % 2 == 0 { t * t % m } else { t * t % m * x % m }
}

fn main2() {
    let p = 17;
    let hoge = [1, 2, 3];
    let mut ys = vec![0; 18];
    for &h in &hoge {
        ys[modpow(h, p-2, p) as usize] += 1;
    }
    for a in 0..p+1 {
        let mut bs = vec![1];
        let mut t = 1;
        loop {
            t = (3 * t) % p;
            bs.push(t);
            if t == 1 {
                break;
            }
        }
        for i in 0..p {
        //for i in &bs {
            print!("{:2} ", a * i % p);
        }        
        let mut t = 0;
        for &i in &hoge {
            t += a * i % p;
        }
        print!("  |  {:4} {}", t, ys[a as usize]);
        println!();
    }
}
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();
                }
            }
        }
    }
}