Problem:
Problem C: Complex Integer Solutions

Let f(x) = a0 + a1x + a2x2 + ... + adxd be the function where each ai (0 ≤ i ≤ d) is a constant integer (and ad is non-zero) and x is a variable. Your task is to write a program that finds all complex integer solutions of the equation f(x) = 0 for a given f(x). Here, by complex integers, we mean complex numbers whose
real and imaginary parts are both integers.

Input

The input consists of two lines. The first line of the input contains d, the degree of f(x). The second line contains (d + 1) integers a0, ... , ad, the coeffcients of the equation. You may assume all the following: 1 ≤ d ≤ 10, |ai| ≤ 106 and ad ≠ 0.

Output

There should be two lines in the output. In the first line, print the number m of complex integer solutions. In the second line, print m solutions separated by space. Each solution should be counted and printed exactly once even if it is a multiple root. The solutions should be printed in ascending order of their real parts then their imaginary parts, and in the following fashion: 0, -2, i, -3i, 2+i, and 3-4i.

Sample Input 1

4
-2 0 0 0 2

Output for the Sample Input 1

4
-1 -i i 1

Sample Input 2

8
0 0 25 15 17 -10 1 -1 1

Output for the Sample Input 2

5
-1-2i -1+2i 0 2-i 2+i

Solution in JAVA (judge verdict: Accepted)

import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;
import static java.util.Collections.*;

// Complex Integer Solutions
// 2012/12/25
public class Main{
	Scanner sc=new Scanner(System.in);

	int n;
	int[] a;

	void run(){
		n=sc.nextInt();
		a=new int[n+1];
		for(int i=n; i>=0; i--){
			a[i]=sc.nextInt();
		}
		solve();
	}

	void solve(){
		int p1=nextPrime(1500), p2=nextPrime(p1);
		int p=p1*p2;

		ArrayList<P> list1=new ArrayList<P>(), list2=new ArrayList<P>();

		for(int x=0; x<p1; x++){
			for(int y=0; y<p1; y++){
				P eval=evalMod(x, y, p1);
				if(eval.x==0&eval.y==0){
					list1.add(new P(x, y));
				}
			}
		}
		for(int x=0; x<p2; x++){
			for(int y=0; y<p2; y++){
				P eval=evalMod(x, y, p2);
				if(eval.x==0&eval.y==0){
					list2.add(new P(x, y));
				}
			}
		}

		// debug("list1", list1);
		// debug("list2", list2);

		TreeSet<P> set=new TreeSet<P>();

		for(P z1 : list1){
			for(P z2 : list2){
				// z = z1 % p1
				// z = z2 % p2
				long x=linear(new long[]{1, 1}, new long[]{z1.x, z2.x},
						new long[]{p1, p2});
				long y=linear(new long[]{1, 1}, new long[]{z1.y, z2.y},
						new long[]{p1, p2});
				// debug(z);
				if(x>abs(x-p)){
					x=x-p;
				}
				if(y>abs(y-p)){
					y=y-p;
				}
				P eval=eval(x, y);
				if(eval.x==0&&eval.y==0){
					set.add(new P(x,y));
				}
				/*
				for(int i=0; i<=1; i++){
					for(int j=0; j<=1; j++){
						P zz=new P(z.x-i*p1*p2, z.y-j*p1*p2);
						// if (zz.x == -1)
						// debug(zz);
						if(eval(zz)){
							set.add(zz);
						}
					}
				}
				*/
			}
		}

		P[] ps=set.toArray(new P[0]);
		StringBuilder sb=new StringBuilder();
		sb.append(ps.length).append('\n');
		for(int i=0; i<ps.length; i++){
			long x=ps[i].x, y=ps[i].y;
			String s=x+"+"+y+"i";
			s=s.replaceAll("[\\+|-]0i", "").replaceAll("\\+-", "-")
					.replaceAll("\\+1i", "+i").replaceAll("-1i", "-i")
					.replaceAll("^0", "").replaceAll("^\\+", "");
			if(s.length()==0){
				s="0";
			}
			sb.append(s);
			if(i==ps.length-1){}else{
				sb.append(' ');
			}
		}
		println(sb.toString());
	}

	long linear(long[] A, long[] B, long[] M){
		long x=0, m=1;
		for(int i=0; i<A.length; i++){
			long a=A[i]*m, b=B[i]-A[i]*x, d=gcd(M[i], a);
			if(b%d!=0)
				return -1;
			long t=b/d*invMod(a/d, M[i]/d)%(M[i]/d);
			x=x+m*t;
			m*=M[i]/d;
		}
		return (x%m+m)%m;
	}

	long gcd(long a, long b){
		return a==0?b:gcd(b%a, a);
	}

	long invMod(long x, long mod){
		return powMod(x, mod-2, mod);
	}

	long powMod(long x, long k, long mod){
		if(k==0){
			return 1;
		}
		if((k&1)==0){
			return powMod(x*x%mod, k>>>1, mod);
		}
		return x*powMod(x, k-1, mod)%mod;
	}

	P evalMod(long x, long y, int mod){
		P eval=new P(0, 0);
		for(int i=0; i<=n; i++){
			mul(eval, x, y);
			add(eval, a[i], 0);
			eval.x%=mod;
			eval.y%=mod;
		}
		return eval;
	}

	P eval(long x, long y){
		P eval=new P(0, 0);
		for(int i=0; i<=n; i++){
			mul(eval, x, y);
			add(eval, a[i], 0);
		}
		return eval;
	}

	void add(P p, long x, long y){
		p.x+=x;
		p.y+=y;
	}

	void mul(P p, long x, long y){
		long nx=p.x*x-y*p.y;
		long ny=x*p.y+y*p.x;
		p.x=nx;
		p.y=ny;
	}

	class P implements Comparable<P>{
		long x, y;

		P(long x, long y){
			this.x=x;
			this.y=y;
		}

		P add(P p){
			return new P(x+p.x, y+p.y);
		}

		P mul(P p){
			return new P(x*p.x-y*p.y, x*p.y+p.x*y);
		}

		public boolean equals(P p){
			return x==p.x&&y==p.y;
		}

		@Override
		public String toString(){
			return "("+x+", "+y+")";
		}

		public int compareTo(P p){
			return Long.signum(x-p.x)*2+Long.signum(y-p.y);
		}
	}

	int nextPrime(int n){
		for(n++; !BigInteger.valueOf(n).isProbablePrime(200); n++);
		return n;
	}

	void println(String s){
		System.out.println(s);
	}

	void print(String s){
		System.out.print(s);
	}

	void debug(Object... os){
		System.err.println(deepToString(os));
	}

	public static void main(String[] args){
		new Main().run();
	}
}