Problem:
Score : 800 points

Problem Statement

You are given a polynomial of degree N with integer coefficients: f(x)=a_Nx^N+a_{N-1}x^{N-1}+...+a_0. Find all prime numbers p that divide f(x) for every integer x.

Constraints

0 \leq N \leq 10^4

|a_i| \leq 10^9(0\leq i\leq N)

a_N \neq 0

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
a_N
:
a_0

Output

Print all prime numbers p that divide f(x) for every integer x, in ascending order.

Sample Input 1

2
7
-7
14

Sample Output 1

2
7

2 and 7 divide, for example, f(1)=14 and f(2)=28.

Sample Input 2

3
1
4
1
5

Sample Output 2

There may be no integers that satisfy the condition.

Sample Input 3

0
998244353

Sample Output 3

998244353

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
using namespace std;
//#define cerr if (false) cerr
#define db(x) cerr << #x << "=" << x << endl
#define db2(x, y) cerr << #x << "=" << x << "," << #y << "=" << y << endl
#define db3(x, y, z) cerr << #x << "=" << x << "," << #y << "=" << y << "," << #z << "=" << z << endl
#define dbv(v) cerr << #v << "="; for (auto _x : v) cerr << _x << ", "; cerr << endl
#define dba(a, n) cerr << #a << "="; for (int _i = 0; _i < (n); ++_i) cerr << a[_i] << ", "; cerr << endl
typedef long long ll;
typedef long double ld;
int MOD;
ll modex(ll a, ll p, ll m) {
	if (!p) return 1;
	if (p & 1) return a * modex(a, p - 1, m) % m;
	ll v = modex(a, p >> 1, m);
	return v * v % m;
}
namespace fft {
struct cpx {
	double r, i;
	cpx(double r = 0, double i = 0) : r(r), i(i) {}
	cpx operator+(cpx b) { return {r + b.r, i + b.i}; }
	cpx operator-(cpx b) { return {r - b.r, i - b.i}; }
	cpx operator*(cpx b) { return {r * b.r - i * b.i, r * b.i + i * b.r}; }
	cpx operator/(double b) { return {r / b, i / b}; }
	inline cpx conj() { return {r, -i}; }
};
const double PI = acos(-1);
vector<int> rev(1, 0); // rev has [base] bits
vector<cpx> roots;
int base = 0;
void precompute(int nbase) {
	if (nbase <= base) return;
	rev.resize(1 << nbase);
	for (int i = 0; i < (1 << nbase); ++i) {
		rev[i] = rev[i >> 1] >> 1 | ((i & 1) << nbase - 1);
	}
	roots.resize(1 << nbase);
	for (; base < nbase; ++base) {
		int len = 1 << base;
		double angle = 2 * PI / (1 << (base + 1));
		for (int i = 0; i < len; ++i) {
			double cur = angle * i;
			roots[len + i] = cpx(cos(cur), sin(cur));
		}
	}
}
void fft(vector<cpx>& a, int n = -1) {
	if (n == -1) n = a.size();
	assert((n & (n - 1)) == 0);
	int zeros = __builtin_ctz(n);
	precompute(zeros);
	int shift = base - zeros;
	for (int i = 0; i < n; ++i) {
		if (i < (rev[i] >> shift)) swap(a[i], a[rev[i] >> shift]);
	}
	for (int len = 1; len < n; len <<= 1)
		for (int i = 0; i < n; i += 2 * len)
			for (int j = 0; j < len; ++j) {
				cpx u = a[i + j], v = a[i + j + len] * roots[len + j];
				a[i + j] = u + v;
				a[i + j + len] = u - v;
			}
}
vector<cpx> fa, fb;
vector<ll> multiply(vector<int> a, vector<int> b) {
	if (a.empty() || b.empty()) return {};
	int sz = a.size() + b.size() - 1;
	int n = sz == 1 ? 1 : 1 << (32 - __builtin_clz(sz - 1));
	if (n > fa.size()) fa.resize(n);
	for (int i = 0; i < n; ++i) {
		int x = i < a.size() ? a[i] : 0;
		int y = i < b.size() ? b[i] : 0;
		fa[i] = cpx(x, y);
	}
	fft(fa, n);
	cpx r(0, -0.5 / n);
	for (int i = 0; i <= (n >> 1); ++i) {
		int j = (n - i) & (n - 1);
		cpx x = (fa[i] + fa[j].conj()) / 2;
		cpx y = (fa[i] - fa[j].conj()) * r;
		fa[i] = x * y;
		if (i != j) fa[j] = fa[i].conj();
	}
	fft(fa, n);
	reverse(fa.begin() + 1, fa.begin() + n);
	vector<ll> res(sz);
	for (int i = 0; i < sz; ++i) {
		res[i] = llround(fa[i].r);
	}
	return res;
}
vector<int> multiply(const vector<int>& a, const vector<int>& b, int m) {
	if (m < (1 << 15)) {
		auto res = multiply(a, b);
		vector<int> ret(res.size());
		for (int i = 0; i < res.size(); ++i) ret[i] = res[i] % m;
		return ret;
	}
	if (a.empty() || b.empty()) return {};
	int eq = (a == b);
	int sz = a.size() + b.size() - 1;
	int n = sz == 1 ? 1 : 1 << (32 - __builtin_clz(sz - 1));
	if (n > fa.size()) fa.resize(n);
	for (int i = 0; i < a.size(); ++i) {
		fa[i] = cpx(a[i] & ((1 << 15) - 1), a[i] >> 15);
	}
	fill(fa.begin() + a.size(), fa.begin() + n, cpx(0, 0));
	fft(fa, n);
	if (n > fb.size()) fb.resize(n);
	if (eq) {
		copy(fa.begin(), fa.begin() + n, fb.begin());
	} else {
		for (int i = 0; i < b.size(); ++i) {
			fb[i] = cpx(b[i] & ((1 << 15) - 1), b[i] >> 15);
		}
		fill(fb.begin() + b.size(), fb.begin() + n, cpx(0, 0));
		fft(fb, n);
	}
	double ratio = 0.5 / n;
	cpx r2(0, -0.5);
	cpx r3(ratio, 0);
	cpx r4(0, -ratio);
	cpx r5(0, 1);
	for (int i = 0; i <= (n >> 1); ++i) {
		int j = (n - i) & (n - 1);
		cpx a1 = (fa[i] + fa[j].conj()) / 2;
		cpx a2 = (fa[i] - fa[j].conj()) * r2;
		cpx b1 = (fb[i] + fb[j].conj()) * r3;
		cpx b2 = (fb[i] - fb[j].conj()) * r4;
		cpx x = a1 * b1;
		cpx y = a2 * b2;
		fa[i] = x + y * r5;
		fb[i] = a1 * b2 + a2 * b1;
		if (i != j) {
			fa[j] = x.conj() + y.conj() * r5;
			fb[j] = fb[i].conj();
		}
	}
	fft(fa, n);
	fft(fb, n);
	reverse(fa.begin() + 1, fa.begin() + n);
	reverse(fb.begin() + 1, fb.begin() + n);
	vector<int> res(sz);
	for (int i = 0; i < sz; ++i) {
		ll aa = llround(fa[i].r);
		ll bb = llround(fb[i].r);
		ll cc = llround(fa[i].i);
		res[i] = (aa + ((bb % m) << 15) + ((cc % m) << 30)) % m;
	}
	return res;
}
}; // namespace fft
namespace polynomial {
// Leading zeros are not possible.
vector<int> subtract(vector<int> a, const vector<int>& b) {
	if (a.size() < b.size()) {
		a.resize(b.size());
	}
	for (int i = 0; i < b.size(); ++i) {
		a[i] -= b[i];
		if (a[i] < 0) a[i] += MOD;
	}
	while (!a.empty() && !a.back()) a.pop_back();
	return a;
}
// Leading zeros are not possible.
vector<int> add(vector<int> a, const vector<int>& b) {
	if (a.size() < b.size()) {
		a.resize(b.size());
	}
	for (int i = 0; i < b.size(); ++i) {
		a[i] += b[i];
		if (a[i] >= MOD) a[i] -= MOD;
	}
	while (!a.empty() && !a.back()) a.pop_back();
	return a;
}
// Invert a power series mod x^n, where f[0] != 0
// P[2n] = P[n](2 - f * P[n]) mod x^(2n)
// O(n log n)
vector<int> inverse(const vector<int>& a) {
#ifdef NTT
	assert(!a.empty() && a[0] != 0 && MOD == fft::mod);
	int n = a.size();
	vector<int> b = {(int)modex(a[0], MOD - 2, MOD)};
	for (int m = 2; b.size() < n; m <<= 1) {
		vector<int> aCut(a.begin(), a.begin() + min((int)a.size(), m));
		aCut.resize(2 * m);
		b.resize(2 * m);
		fft::fft(aCut);
		fft::fft(b);
		for (int i = 0; i < 2 * m; ++i) {
			b[i] = b[i] * (2 - (ll)aCut[i] * b[i] % MOD) % MOD;
			if (b[i] < 0) b[i] += MOD;
		}
		fft::fft(b);
		reverse(b.begin() + 1, b.end());
		b.resize(m);
		ll inv = modex(2 * m, MOD - 2, MOD);
		for (int i = 0; i < m; ++i) b[i] = b[i] * inv % MOD;
	}
	b.resize(n);
	return b;
#else
	assert(!a.empty() && a[0] != 0);
	int n = a.size();
	vector<int> b = {(int)modex(a[0], MOD - 2, MOD)};
	for (int m = 2; b.size() < n; m <<= 1) {
		vector<int> aCut(a.begin(), a.begin() + min((int)a.size(), m));
		auto x = fft::multiply(aCut, fft::multiply(b, b, MOD), MOD);
		b.resize(m);
		for (int i = 0; i < m; ++i) {
			b[i] += b[i] - x[i];
			if (b[i] >= MOD) b[i] -= MOD;
			if (b[i] < 0) b[i] += MOD;
		}
	}
	b.resize(n);
	return b;
#endif
}
// Polynomial division: divide A (<= deg n) by B (deg m)
// A(x) = Q(x)B(x) + R(x), deg Q <= n-m. Substitute x = 1/x.
// x^nA(1/x) = (x^(n-m)Q(1/x))(x^mB(1/x)) + x^(n-m+1)(x^(m-1)R(1/x))
// Note x^deg * poly(1/x) = poly_reverse(x).
// So A_rev(x) = Q_rev(x)B_rev(x) mod x^(n-m+1).
// So we can recover Q, since deg Q_rev <= n-m.
// Leading zeros are not possible if A has no leading zeros.
// O(n log n)
vector<int> divide(vector<int> a, vector<int> b) {
	assert(!b.empty() && b.back() != 0);
	int n = a.size();
	int m = b.size();
	if (n < m) return {};
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	b.resize(n - m + 1);
	a = fft::multiply(a, inverse(b), MOD);
	a.erase(a.begin() + n - m + 1, a.end());
	reverse(a.begin(), a.end());
	return a;
}
// O(n log n) where n = deg a. Leading zeros are not possible.
vector<int> remainder(const vector<int>& a, const vector<int>& b) {
	return subtract(a, fft::multiply(b, divide(a, b), MOD));
}
// Calculate integral with c=0. Leading zeros are possible!
vector<int> integral(const vector<int>& a) {
	vector<int> ret(a.size() + 1);
	for (int i = 1; i < ret.size(); ++i) {
		ret[i] = a[i - 1] * modex(i, MOD - 2, MOD) % MOD;
	}
	return ret;
}
// Leading zeros are possible!
vector<int> derivative(const vector<int>& a) {
	if (a.empty()) return a;
	vector<int> ret(a.size() - 1);
	for (int i = 0; i + 1 < a.size(); ++i)
		ret[i] = (ll)a[i + 1] * (i + 1) % MOD;
	return ret;
}
// Calculate log(f) mod x^n, where f[0] == 1. ret[0] == 0.
// O(n log n)
vector<int> logarithm(const vector<int>& a) {
	assert(!a.empty() && a[0] == 1);
	auto ret = integral(fft::multiply(derivative(a), inverse(a), MOD));
	ret.resize(a.size());
	return ret;
}
// Calculate exp(f) mod x^n, where f[0] == 0. ret[0] == 1.
// P[2n] = P[n](1 - log(P[n]) + f) mod x^(2n)
// O(n log n)
vector<int> exponent(const vector<int>& a) {
	assert(!a.empty() && a[0] == 0);
	int n = a.size();
	vector<int> b = {1};
	for (int m = 2; b.size() < n; m <<= 1) {
		vector<int> x(a.begin(), a.begin() + min((int)a.size(), m));
		++x[0];
		if (x[0] >= MOD) x[0] -= MOD;
		auto oldB = b;
		b.resize(m);
		b = fft::multiply(oldB, subtract(x, logarithm(b)), MOD);
		b.resize(m);
	}
	b.resize(n);
	return b;
}
// Multipoint evaluation: Evaluate A (deg d) at n points xs modulo MOD.
// Key idea: A(x_i) = A(x) mod (x - x_i).
// Calculate A mod (x-x_l)...(x-x_r) for range [l,r].
// O(n log^2 n + d log d)
vector<int> multipoint(const vector<int>& a, vector<int> xs) {
	int n = xs.size();
	vector<vector<int>> prods(2 * n - 1);
	function<void(int, int, int)> getProds = [&](int sn, int s, int e) {
		if (s == e) {
			prods[sn] = {xs[s] ? MOD - xs[s] : 0, 1};
			return;
		}
		int m = (s + e) >> 1, lsn = sn + 1, rsn = sn + ((m - s + 1) << 1);
		getProds(lsn, s, m);
		getProds(rsn, m + 1, e);
		prods[sn] = fft::multiply(prods[lsn], prods[rsn], MOD);
	};
	getProds(0, 0, n - 1);
	function<void(int, int, int, vector<int>)> calc = [&](int sn, int s, int e, vector<int> f) {
		if (s == e) {
			xs[s] = f.empty() ? 0 : f[0];
			return;
		}
		int m = (s + e) >> 1, lsn = sn + 1, rsn = sn + ((m - s + 1) << 1);
		calc(lsn, s, m, remainder(f, prods[lsn]));
		calc(rsn, m + 1, e, remainder(f, prods[rsn]));
	};
	calc(0, 0, n - 1, a);
	return xs;
}
// Given a polynomial A and generator g, evaluate Y[k] = A(g^k) for all 0 <= k < n.
// A(g^(2k)) = sum_i a_i * g^(2ki)
// A(g^(2k+1)) = sum_i a_i * g^i * g^(2ki)
// Chirp z-transform: g^(2ki) = g^(kk) g^(ii) g^(-(k-i)^2); so we can convolve.
// O(MOD + (n + deg A) log (n + deg A))
vector<int> chirpz(vector<int> a, int g, int n) {
	int d = a.size();
	int phi = MOD - 1;
	vector<ll> pw(phi + 1, 1);
	for (int i = 1; i <= phi; ++i) pw[i] = pw[i - 1] * g % MOD;
	auto chirpzEven = [&](const vector<int>& b, int m) {
		vector<int> u(d), v(m + d - 1);
		for (int i = 0; i < d; ++i) {
			u[i] = b[i] * pw[(ll)i * i % phi] % MOD;
		}
		for (int i = -(d - 1); i < m; ++i) {
			v[d - 1 + i] = pw[phi - (ll)i * i % phi];
		}
		auto z = fft::multiply(u, v, MOD);
		vector<int> ret(m);
		for (int i = 0; i < m; ++i) {
			ret[i] = pw[(ll)i * i % phi] * z[d - 1 + i] % MOD;
		}
		return ret;
	};
	auto even = chirpzEven(a, (n + 1) >> 1);
	for (int i = 0; i < d; ++i) a[i] = a[i] * pw[i % phi] % MOD;
	auto odd = chirpzEven(a, n >> 1);
	vector<int> ret(n);
	for (int i = 0; i < n; ++i) {
		ret[i] = (i & 1) ? odd[i >> 1] : even[i >> 1];
	}
	return ret;
}
// Compute A^p mod B in O(b log b log p).
vector<int> powerMod(vector<int>& a, ll p, vector<int>& b) {
	if (!p) return {1};
	vector<int> c;
	if (p & 1) {
		c = fft::multiply(powerMod(a, p - 1, b), a, MOD);
	} else {
		c = powerMod(a, p >> 1, b);
		c = fft::multiply(c, c, MOD);
	}
	return remainder(c, b);
}
// Compute A^p mod x^n in O(n log n) using exp/log.
vector<int> power(vector<int> a, ll p, int n) {
	if (!p) return {1};
	assert(a.size() <= n);
	int m = 0;
	while (m < a.size() && a[m] == 0) ++m;
	if (m * p >= n) return {};
	a.erase(a.begin(), a.begin() + m);
	ll inv = modex(a[0], MOD - 2, MOD);
	ll c = modex(a[0], p, MOD);
	for (int& x : a) x = x * inv % MOD;
	a = logarithm(a);
	ll q = p % MOD;
	for (int& x : a) x = x * q % MOD;
	a = exponent(a);
	a.insert(a.begin(), min(n - (ll)a.size(), m * p), 0);
	for (int& x : a) x = x * c % MOD;
	return a;
}
}; // namespace polynomial
using namespace polynomial;
int primitiveRoot(int n) {
	vector<int> fact;
	int phi = n - 1, x = phi;
	for (int i = 2; i * i <= x; ++i)
		if (x % i == 0) {
			fact.push_back(i);
			while (x % i == 0)
				x /= i;
		}
	if (x > 1) fact.push_back(x);
	for (int res = 1; res <= n; ++res) {
		bool ok = true;
		for (int i = 0; i < fact.size() && ok; ++i)
			ok &= modex(res, phi / fact[i], n) != 1;
		if (ok) return res;
	}
	return -1;
}
int main() {
	int n;
	scanf("%d", &n);
	vector<int> a(n + 1);
	for (int i = n; i >= 0; --i) scanf("%d", &a[i]);
	vector<int> factors;
	int x = abs(a[0]);
	int p = 2;
	while (p * p <= x) {
		if (x % p == 0) {
			do {
				x /= p;
			} while (x % p == 0);
			factors.push_back(p);
		}
		++p;
	}
	if (x > 1) factors.push_back(x);
	for (int f : factors) {
		if (f > n) {
			bool bad = false;
			for (int i = 0; i <= n; ++i) if (a[i] % f) bad = true;
			if (!bad) printf("%d\n", f);
			continue;
		}
		int g = primitiveRoot(f);
		auto b = a;
		for (int i = 0; i <= n; ++i) {
			b[i] = (a[i] % f + f) % f;
		}
		MOD = f;
		auto ev = chirpz(b, g, f);
		bool bad = false;
		for (int i = 0; i < f; ++i) {
			if (ev[i] != 0) bad = true;
		}
		if (!bad) printf("%d\n", f);
	}
}