Problem:
有限体電卓

0以外のすべての実数の逆数は実数になりますが、整数の逆数が整数になるとは限りません。Ｃ言語などで 3.0/2.0*2.0 = 3.0 なのに 3/2*2 = 2 になってしまうのはこのためです。ですが、素数で割った余りが等しい整数を同じものとみなすと、0以外のすべての整数が逆数をもつようにできます。

整数 x と y を p で割った余りが等しいとき、x ≡ y (mod p) と書きます。p が素数のとき、このような x と y を同じものとみなすなら、すべての整数 n は0から p−1 までのどれかの整数 x に対して x ≡ n (mod p) となるので、けっきょく { 0, 1, 2, ..., p−1 } という集合だけからなる世界を考えればよいことがわかります。

この世界での加減乗除は以下のようになります。

加算 x+y の値は、x+y ≡ z (mod p) となる 0 から p−1 までの数 z になります。

減算 x−yの値は、y+m ≡ 0 (mod p) となる 0 から p−1 までの数 m（これが y に相当します）について、x−y ≡ x + m (mod p) となることから得られます。たとえば、p = 5のとき、4+1 ≡ 0 (mod 5) となります。このとき、2−4 ≡ 2+1 ≡ 3 (mod 5) より、2−4の値は3になります。

乗算 x*y の値は、x*y ≡ z (mod p) となる 0 から p−1 までの数 z になります。

除算 x/y の値は、y*d ≡ 1 (mod p)となる 0 から p−1 までの数 d （これがyの逆数になります）について、x/y ≡ x*d (mod p) となることから得られます。たとえば、p = 5 のとき、2*3 ≡ 1 (mod 5) より 3 は 2 の逆数になります。このとき、1/2 ≡ 1*3 ≡ 3 (mod 5) より、1/2 の値は 3 になります。

このようにして加減乗除の四則演算がすべて0からp−1の範囲に収まります。このとき、集合 { 0,1,...,p−1 } を p の有限体といいます。この有限体の中で、加減乗除、0 から p−1 までの数、カッコを使って 算術式を構成することができます。

p の有限体の 0 以外のすべての要素が逆数をもつことは、フェルマーの小定理と呼ばれる有名な定理 ap−1 ≡ 1 (mod p) からわかります（ただし、p は素数、a と p は互いに素）。p の有限体のすべての要素 x は p と互いに素なので、この定理から x*xp-2 ≡ 1 (mod p) となり xp-2 が x の逆数になるからです。

では、素数と式が与えられたときに、その素数の有限体で式を計算する電卓プログラムを作成してください。

入力

入力は複数のデータセットからなる。入力の終わりは0の後にコロンが１つ続くだけの行 0: で示される。各データセットは以下の形式で与えられる。

p:exp

データセットは１行であり、p (2 ≤ p ≤ 46000) は素数、exp は算術式を示す。exp は加減乗除（それぞれ +, -, *, /）とカッコ、0 から p−1 までの数から構成される。演算子、数、カッコなどの前後には1つ以上の空白が現れる可能性がある。exp の長さは 100,000 を超えない。

データセットの数は 1000 を超えない。

出力

データセットごとに、計算結果を出力する。出力形式は以下の通りである。

exp = val (mod p)

val は、p の有限体での算術式 exp の計算結果である。ただし、0 での除算が含まれるときは NG と出力する。また、exp に現れる加減乗除、カッコ、数の前後には空白を空けないこと。ただし、= の前後には空白を一つずつ空ける。また、valと開きカッコの間、modとp の間にも空白を一つずつ空ける。

入力例

5: 2 - 3
17: 1 + 3 * (2 + 3 / 5 * 2) + 7
11: 1 / 8 - 5 - 8 * 2
19: 8 / (2 - 3 * 7)
1153: 10 * 3 / 7 + ( 50 + 81 / 22 ) + 11
0:

出力例

2-3 = 4 (mod 5)
1+3*(2+3/5*2)+7 = 4 (mod 17)
1/8-5-8*2 = 8 (mod 11)
NG
10*3/7+(50+81/22)+11 = 915 (mod 1153)

Solution in JAVA (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

	public static final int SIZE = 100000;
	public static int[] queue = new int[SIZE + 1];
	public static int tp = 0;
	public static int bp = 0;

	public static int next_index(int index) {
		return (index + 1) % SIZE;
	}

	public static int prev_index(int index) {
		return (SIZE + index - 1) % SIZE;
	}

	public static void push(int x) {
		queue[tp] = x;
		tp = next_index(tp);
	}

	public static int pop() {
		int old = bp;
		bp = next_index(bp);
		return queue[old];
	}

	public static int peek() {
		return queue[bp];
	}

	public static void del() {
		bp = next_index(bp);
	}

	public static int size() {
		return tp - bp;
	}

	public static boolean is_empty() {
		return tp == bp;
	}

	public static void clean() {
		tp = bp = 0;
	}

	public static final int ADD = -1;
	public static final int SUB = -2;
	public static final int MUL = -3;
	public static final int DIV = -4;
	public static final int KAKKO_L = -5;
	public static final int KAKKO_R = -6;

	public static int mod_pow(int x, int p, int mod) {
		if (p == 1) {
			return x % mod;
		} else if (p == 0) {
			return x == 1 ? 1 : 0;
		}

		if (p % 2 == 0) {
			int ret = mod_pow(x, p / 2, mod);

			return (ret * ret) % mod;
		} else {
			return (mod_pow(x, p - 1, mod) * x) % mod;
		}
	}

	// +, -
	public static int calc_parse_1(int mod) {
		int left = calc_parse_2(mod);

		if (left < 0) {
			return Integer.MIN_VALUE;
		}
		// System.out.println("t");

		while (!is_empty()) {
			if (!(peek() == ADD) && !(peek() == SUB)) {
				return left;
			}

			int type = pop();
			int right = calc_parse_2(mod);

			if(left < 0 || right < 0){
				return Integer.MIN_VALUE;
				//left = Integer.MIN_VALUE;
			}else if (type == ADD) {
				left = (left + right) % mod;
			} else {
				left = (mod + left - right) % mod;
			}
		}
		return left;
	}

	// *, /
	public static int calc_parse_2(int mod) {
		int left = calc_parse_3(mod);
		
		if (left < 0) {
			return Integer.MIN_VALUE;
		}

		while (!is_empty()) {
			if (!(peek() == MUL) && !(peek() == DIV)) {
				return left;
			}

			int type = pop();
			int right = calc_parse_3(mod);
			
			if(left < 0 || right < 0){
				return Integer.MIN_VALUE;
				//left = Integer.MIN_VALUE;
			}else if(type == MUL) {
				left = (left * right) % mod;
			}else if(right == 0){
				return Integer.MIN_VALUE;
				//left = Integer.MIN_VALUE;
			}else {
				final int inv = mod_pow(right, mod - 2, mod);
				
				if(inv == 0){
					return Integer.MIN_VALUE;
					//left = Integer.MIN_VALUE;
				}else{
					left = (left * inv) % mod;
				}
			}
		}
		return left;
	}

	// primitive, ()
	public static int calc_parse_3(int mod) {
		if (is_empty()) {
			return Integer.MIN_VALUE;
		} else if (peek() >= 0) {
			int number = pop();
			return number;
		} else if (peek() == KAKKO_L) {
			del();
			int expr = calc_parse_1(mod);

			if (peek() == KAKKO_R) {
				del();
				return expr;
			} else {
				return Integer.MIN_VALUE;
			}
		}

		return Integer.MIN_VALUE;
	}
	
	public static void add_stack(String line) {
		clean();
		char[] input = line.toCharArray();

		int count = -1;
		for (char c : input) {
			if ('0' <= c && c <= '9') {
				if (count == -1) {
					count = 0;
				}

				count *= 10;
				count += c - '0';
			} else {
				if (count != -1) {
					push(count);
				}
				count = -1;
			}

			switch (c) {
			case '+':
				push(ADD);
				break;
			case '-':
				push(SUB);
				break;
			case '*':
				push(MUL);
				break;
			case '/':
				push(DIV);
				break;
			case '(':
				push(KAKKO_L);
				break;
			case ')':
				push(KAKKO_R);
				break;
			}

			// System.out.println(stack);
		}

		if (count != -1) {
			push(count);
		}
	}

	public static void main(String[] args) throws IOException {
		// Scanner sc = new Scanner(System.in);

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		//int count = 0;

		while (true) {
			String input = br.readLine();

			if ("0:".equals(input)) {
				break;
			}
			// count++;

			// if(count > 4){
			// count = 0;
			// System.gc();
			// }
			//System.gc();

			String[] in = input.split(":");
			// String[] tokens = in[1].split(" ");

			// System.out.println(Arrays.toString(tokens));

			// stack.clear();
			/*
			 * for(int i = 0; i < tokens.length; i++){ if(tokens[i].equals("")
			 * || tokens[i].equals(" ")){ continue; }
			 * 
			 * add_stack(tokens[i], stack); }
			 */

			add_stack(in[1]);
			// System.out.println(stack);

			final int mod = Integer.parseInt(in[0]);

			// Expr node = parse_1();

			//System.out.println(disp_parse_1());
			
			int result = calc_parse_1(mod);
			
			if(result < 0){
				System.out.println("NG");
			}else{
				System.out.println(in[1].replaceAll(" ", "") + " = " + result + " (mod " + mod + ")");
			}
			
		}

		br.close();
	}
}