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: Memory Limit Exceeded)

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
	
	//public static final int NUMBER  = 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 final Token ADD_TOK = new Token("+", ADD);
	public static final Token SUB_TOK = new Token("-", SUB);
	public static final Token MUL_TOK = new Token("*", MUL);
	public static final Token DIV_TOK = new Token("/", DIV);
	public static final Token KAKKO_L_TOK = new Token("(", KAKKO_L);
	public static final Token KAKKO_R_TOK = new Token(")", KAKKO_R);
	
	public static class Token{
		String value;
		int type;
		
		public Token(String value, int type) {
			super();
			this.value = value;
			this.type = type;
		}
		
		public String toString(){
			return "[ " + this.value + " " + this.type + " ]";
		}
	}
	
	public static interface Expr{
		public int eval(int mod);
	}
	
	public static class Inner implements Expr{
		Expr inner;

		public Inner(Expr inner) {
			super();
			this.inner = inner;
		}

		@Override
		public int eval(int mod) {
			return inner.eval(mod) % mod;
		}
		
		@Override
		public String toString(){
			return "(" + inner +  ")";
		}
	}
	
	public static class Plus implements Expr{
		Expr left, right;

		public Plus(Expr left, Expr right) {
			super();
			this.left = left;
			this.right = right;
		}

		@Override
		public int eval(int mod) {
			return (left.eval(mod) + right.eval(mod)) % mod;
		}
		
		@Override
		public String toString(){
			return left + "+" + right;
		}
	}
	
	public static class Minus implements Expr{
		Expr left, right;

		public Minus(Expr left, Expr right) {
			super();
			this.left = left;
			this.right = right;
		}

		@Override
		public int eval(int mod) {
			return (mod + left.eval(mod) - right.eval(mod)) % mod;
		}
		
		@Override
		public String toString(){
			return left + "-" + right;
		}
	}
	
	public static class Mul implements Expr{
		Expr left, right;

		public Mul(Expr left, Expr right) {
			super();
			this.left = left;
			this.right = right;
		}

		@Override
		public int eval(int mod) {
			return (left.eval(mod) * right.eval(mod)) % mod;
		}
		
		@Override
		public String toString(){
			return left + "*" + right;
		}
	}
	
	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 class Div implements Expr{
		Expr left, right;

		public Div(Expr left, Expr right) {
			super();
			this.left = left;
			this.right = right;
		}

		@Override
		public int eval(int mod) {
			final int right_ret = right.eval(mod);
			
			if(right_ret == 0){
				throw new ArithmeticException("");
			}
			
			int inv = mod_pow(right_ret, mod - 2, mod);
			
			if(inv == 0){
				throw new ArithmeticException("");
			}
			
			return (left.eval(mod) * inv) % mod;
		}
		
		@Override
		public String toString(){
			return left + "/" + right;
		}
	}
	
	public static class Const implements Expr{
		int cons;
		
		public Const(int cons){
			this.cons = cons;
		}
		
		@Override
		public int eval(int mod){
			return cons;
		}
		
		@Override
		public String toString(){
			return cons + "";
		}
	}
	
	//+, -
	public static Expr parse_1(LinkedList<Token> tokens){
		Expr left = parse_2(tokens);
		
		if(left == null){
			return null;
		}
		
		while(!tokens.isEmpty()){
			if(!(tokens.peek().type == ADD) && !(tokens.peek().type == SUB)){
				return left;
			}
			
			int type = tokens.poll().type;
			Expr right = parse_2(tokens);
			
			if(type == ADD){
				left = new Plus(left, right);
			}else{
				left = new Minus(left, right);
			}
		}
		
		return left;
	}
	
	//*, /
	public static Expr parse_2(LinkedList<Token> tokens){
		Expr left = parse_3(tokens);
		
		if(left == null){
			return null;
		}
		
		while(!tokens.isEmpty()){
			if(!(tokens.peek().type == MUL) && !(tokens.peek().type == DIV)){
				return left;
			}
			
			int type = tokens.poll().type;
			Expr right = parse_3(tokens);
			
			if(type == MUL){
				left = new Mul(left, right);
			}else{
				left = new Div(left, right);
			}
		}
		
		return left;
	}
	
	//primitive, ()
	public static Expr parse_3(LinkedList<Token> tokens){
		if(tokens.isEmpty()){
			return null;
		}else if(tokens.peek().type >= 0){
			return new Const(tokens.poll().type);
		}else if(tokens.peek().type == KAKKO_L){
			tokens.poll();
			Expr expr = parse_1(tokens);
			
			if(tokens.peek().type == KAKKO_R){
				tokens.poll();
				return new Inner(expr);
			}else{
				return null;
			}			
		}
		
		return null;
	}
	
	public static void add_stack(String line, LinkedList<Token> stack){
		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){
					stack.add(new Token("", count));
				}
				count = -1;
			}
			
			switch(c){
			case '+':
				stack.add(ADD_TOK);
				break;
			case '-':
				stack.add(SUB_TOK);
				break;
			case '*':
				stack.add(MUL_TOK);
				break;
			case '/':
				stack.add(DIV_TOK);
				break;
			case '(':
				stack.add(KAKKO_L_TOK);
				break;
			case ')':
				stack.add(KAKKO_R_TOK);
				break;
			}
			
			//System.out.println(stack);
		}
		
		if(count != -1){
			stack.add(new Token("", count));
		}
	}
	/*
	public static void add_stack_old(String token, LinkedList<Token> stack){
		if(token.indexOf("+") >= 0){
			if(token.length() == 1){
				stack.add(ADD_TOK);
				return;
			}else{
				final int pos = token.indexOf("+");
				
				if(pos > 0){
					add_stack(token.substring(0, pos), stack);
				}
					
				stack.add(ADD_TOK);
				
				if(pos + 1 < token.length()){
					add_stack(token.substring(pos + 1, token.length()), stack);
				}
			}
		}else if(token.indexOf("-") >= 0){
			if(token.length() == 1){
				stack.add(SUB_TOK);
				return;
			}else{
				final int pos = token.indexOf("-");
				
				if(pos > 0){
					add_stack(token.substring(0, pos), stack);
				}
					
				stack.add(SUB_TOK);
				
				if(pos + 1 < token.length()){
					add_stack(token.substring(pos + 1, token.length()), stack);
				}
			}
		}else if(token.indexOf("*") >= 0){
			if(token.length() == 1){
				stack.add(MUL_TOK);
				return;
			}else{
				final int pos = token.indexOf("*");
				
				if(pos > 0){
					add_stack(token.substring(0, pos), stack);
				}
					
				stack.add(MUL_TOK);
				
				if(pos + 1 < token.length()){
					add_stack(token.substring(pos + 1, token.length()), stack);
				}
			}
		}else if(token.indexOf("/") >= 0){
			if(token.length() == 1){
				stack.add(DIV_TOK);
				return;
			}else{
				final int pos = token.indexOf("/");
				
				if(pos > 0){
					add_stack(token.substring(0, pos), stack);
				}
					
				stack.add(DIV_TOK);
				
				if(pos + 1 < token.length()){
					add_stack(token.substring(pos + 1, token.length()), stack);
				}
			}
		}else if(token.indexOf("(") >= 0){
			if(token.length() == 1){
				stack.add(KAKKO_L_TOK);
				return;
			}else{
				final int pos = token.indexOf("(");
				
				if(pos > 0){
					add_stack(token.substring(0, pos), stack);
				}
					
				stack.add(KAKKO_L_TOK);
				
				if(pos + 1 < token.length()){
					add_stack(token.substring(pos + 1, token.length()), stack);
				}
			}
		}else if(token.indexOf(")") >= 0){
			if(token.length() == 1){
				stack.add(KAKKO_R_TOK);
				return;
			}else{
				final int pos = token.indexOf(")");
				
				if(pos > 0){
					add_stack(token.substring(0, pos), stack);
				}
					
				stack.add(KAKKO_R_TOK);
				
				if(pos + 1 < token.length()){
					add_stack(token.substring(pos + 1, token.length()), stack);
				}
			}
		}else {
			stack.add(new Token(token, 0));
		}
	}
	*/
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		LinkedList<Token> stack = new LinkedList<Token>();
		int count = 0;
		
		while(true){
			String input = sc.nextLine();
			
			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], stack);
			//System.out.println(stack);
			
			final int mod = Integer.parseInt(in[0]);
			
			Expr node = parse_1(stack);
			
			try{
				int result = node.eval(mod);
				
				System.out.println(node + " = " + result + " (mod " + mod + ")");
			}catch(ArithmeticException e){
				System.out.println("NG");
			}catch(NullPointerException e){
				System.err.println(input + "\n" + "\n" + stack);
			}
		}
		
		sc.close();
	}
}