Problem:
Score : 500 points

Problem Statement

We have N integers. The i-th number is A_i.

\{A_i\} is said to be pairwise coprime when GCD(A_i,A_j)=1 holds for every pair (i, j) such that 1\leq i < j \leq N.

\{A_i\} is said to be setwise coprime when \{A_i\} is not pairwise coprime but GCD(A_1,\ldots,A_N)=1.

Determine if \{A_i\} is pairwise coprime, setwise coprime, or neither.

Here, GCD(\ldots) denotes greatest common divisor.

Constraints

2 \leq N \leq 10^6

1 \leq A_i\leq 10^6

Input

Input is given from Standard Input in the following format:

N
A_1 \ldots A_N

Output

If \{A_i\} is pairwise coprime, print pairwise coprime; if \{A_i\} is setwise coprime, print setwise coprime; if neither, print not coprime.

Sample Input 1

3
3 4 5

Sample Output 1

pairwise coprime

GCD(3,4)=GCD(3,5)=GCD(4,5)=1, so they are pairwise coprime.

Sample Input 2

3
6 10 15

Sample Output 2

setwise coprime

Since GCD(6,10)=2, they are not pairwise coprime. However, since GCD(6,10,15)=1, they are setwise coprime.

Sample Input 3

3
6 10 16

Sample Output 3

not coprime

GCD(6,10,16)=2, so they are neither pairwise coprime nor setwise coprime.

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

fn main() {
	let mut s = String::new();
	use std::io::Read;
	std::io::stdin().read_to_string(&mut s).unwrap();
	let mut s = s.split_whitespace();
	let n: usize = s.next().unwrap().parse().unwrap();
	let a: Vec<i64> = s.take(n).map(|a| a.parse().unwrap()).collect();
	let sieve = Sieve::new(1000000);
	let primes: Vec<i64> = sieve.primes().collect();
	let mut cnt = vec![0; 1000000];

	for &a in a.iter() {
		if sieve.is_prime(a as usize) {
			cnt[a as usize] += 1;
		} else {
			let mut n = a;
			for &p in primes.iter() {
				if p * p > n {
					break;
				}
				if n % p == 0 {
					cnt[p as usize] += 1;
					while n % p == 0 {
						n /= p;
					}
				}
			}
			if n > 1 {
				cnt[n as usize] += 1;
			}
		}
	}

	let mut ty = 0;
	for &p in primes.iter() {
		if cnt[p as usize] == n {
			ty = 2;
			break;
		}
		if cnt[p as usize] > 1 {
			ty = 1;
		}
	}

	let s = match ty {
		0 => "pairwise coprime",
		1 => "setwise coprime",
		2 => "not coprime",
		_ => unreachable!(),
	};
	println!("{}", s);
}


pub struct Sieve {
	sieve: Vec<u64>,
	n: usize,
}

impl Sieve {
	const BIT_LENGTH: usize = std::mem::size_of::<u64>() * 8;

	pub fn new(n: usize) -> Self {
		let base = (1..Self::BIT_LENGTH).step_by(2).fold(0, |r, i| r | 1 << i);
		let mut sieve = vec![base; n / Self::BIT_LENGTH + 1];
		sieve[0] ^= 0b0110;
		for p in (3..).step_by(2).take_while(|&i| i * i < n) {
			if sieve[p / Self::BIT_LENGTH] & (1 << p % Self::BIT_LENGTH) != 0 {
				for q in (p * p..=n).step_by(2 * p) {
					sieve[q / Self::BIT_LENGTH] &= std::u64::MAX ^ (1 << q % Self::BIT_LENGTH);
				}
			}
		}
		let r = n % Self::BIT_LENGTH;
		*sieve.last_mut().unwrap() &= ((1 << r) - 1) | 1 << r;
		Self { sieve, n }
	}

	pub fn is_prime<T>(&self, p: T) -> bool
	where
		T: std::convert::TryInto<usize>,
	{
		if let Ok(p) = p.try_into() {
			assert!(p <= self.n);
			self.sieve[p / Self::BIT_LENGTH] & (1 << p % Self::BIT_LENGTH) != 0
		} else {
			false
		}
	}

	pub fn primes<'a, T>(&'a self) -> impl 'a + std::iter::Iterator<Item = T>
	where
		T: std::convert::TryFrom<usize>,
	{
		let mut it = self.sieve.iter();
		let mut bits = 0;
		let mut p = 0;
		std::iter::from_fn(move || {
			while bits == 0 {
				if let Some(next) = it.next().cloned() {
					bits = next;
					p += Self::BIT_LENGTH;
				} else {
					return None;
				}
			}
			let lsb = bits & 0u64.wrapping_sub(bits);
			bits ^= lsb;
			let q = (p - Self::BIT_LENGTH) + lsb.trailing_zeros() as usize;

			T::try_from(q).ok()
		})
	}
}