AOJ 1322 ASCII Expression
問題
2次元で与えられた分数と累乗を含む式をmod2011で計算せよ。
詳しい文法はBNF記法で与えられる。
制約条件
式は20行以下
各行は80文字以下
方針
普通の構文解析っぽくやればいい。
分数の分子と分母は、--------の線の厳密に内側に入っているので結構やりやすい。
いつもの構文解析っぽく、今まで終わった文字数をグローバル変数のpとして持つと、
解析ができないので、関数の引数に(左, 上), (右, 下)の座標を持たせてやる。
引数を参照型にして、終わったところを伝播させる。
ソースコード
const int mod = 2011; int pow(int n, int m){ int res = 1; for(; m; m /= 2){ if(m & 1) res = res * n % mod; n = n * n % mod; } return res; } int inv(int n){ return pow(n, mod - 2); } int n; string in[20]; int expr(int&, int&, int&, int&); int f(int y, int x, int Y, int X){ int res = -1; for(int i = y; i < Y; i++) if(in[i][x] != '.'){ res = res == -1 ? i : -2; } return res; } int powexpr(int &y, int &x, int &Y, int &X){ int p, res; while(x < X && (p = f(y, x, Y, X)) < 0) x++; if(in[p][x] == '('){ x++; res = expr(y, x, Y, X); x++; } else{ res = 0; while(x < X && isdigit(in[p][x])) res *= 10, res += in[p][x++] - '0'; } if(x < X){ p = f(y, x, Y, X); if(p >= 0){ int e = 0; while(x < X && isdigit(in[p][x])) e *= 10, e += in[p][x++] - '0'; res = pow(res, e); } } return res; } int factor(int &y, int &x, int &Y, int &X){ int p; bool sign = 0; while(1){ while(x < X && (p = f(y, x, Y, X)) < 0) x++; if(x + 1 < X && in[p][x] == '-' && in[p][x + 1] == '.') sign ^= 1, x += 2; else break; } if(x + 1 < X && in[p][x] == '-' && in[p][x + 1] == '-'){ int q = x; while(q < X && in[p][q] == '-') q++; int a = y, b = x + 1, c = p, d = q - 1; int num = expr(a, b, c, d); a = p + 1, b = x + 1, c = Y, d = q - 1; int den = expr(a, b, c, d); num = num * inv(den) % mod; x = q + 1; return sign ? (mod - num) % mod : num; } return ((sign ? -1 : 1) * powexpr(y, x, Y, X) % mod + mod) % mod; } int term(int &y, int &x, int &Y, int &X){ int res = inf, p; while(1){ while(x < X && (p = f(y, x, Y, X)) < 0) x++; int a = factor(y, x, Y, X); res = res == inf ? a : (a * res) % mod; p = 0; while(x < X && (p = f(y, x, Y, X)) < 0) x++; if(p < 0 || x >= X || in[p][x] != '*') break; x++; } return res; } int expr(int &y, int &x, int &Y, int &X){ int res = 0, p, op = 0; while(1){ while(x < X && (p = f(y, x, Y, X)) < 0) x++; int a = term(y, x, Y, X); (res += op ? mod - a : a) %= mod; p = 0; while(x < X && (p = f(y, x, Y, X)) < 0) x++; if(p < 0 || x >= X || in[p][x] != '+' && in[p][x] != '-') break; op = in[p][x] == '-'; x++; } return res; } int main(){ while(cin >> n, n){ rep(i, n) cin >> in[i]; int y = 0, x = 0, Y = n, X = in[0].size(); cout << expr(y, x, Y, X) << endl; } return 0; }