AOJ 1322 - ASCII Expression
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1322
概要
与えられた BNF に従った二次元で表現された n 個の数式を評価した値を modulo 2011 で答える.
制約
- n <= 20
- 各行の長さ <= 80
解法
二次元のパースということでかなり重い実装に見えるが,
- top
- base
- bottom
の状態が追加されただけで普通に LL(1) なパースをすればいい.
通常は base の行だけを見て処理をし,fraction のときは top, bottom を base の上側と下側に分けて,それぞれの間で base を見つけ,再帰的にパースする.
x/y modulo 2011 はフェルマーの小定理から x * y^2009 で計算できる.
aoj/1322.cc1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 static const int M = 2011; 5 6 int powmod(int a, int n) 7 { 8 if (n == 0) { 9 return 1; 10 } else if (n & 1) { 11 return (a * powmod(a, n-1))%M; 12 } else { 13 const int e = powmod(a, n>>1); 14 return (e * e)%M; 15 } 16 } 17 18 struct parser 19 { 20 int i; 21 vector<string> src; 22 parser() : i(0), src() {} 23 24 int width() const { return src[0].size(); } 25 int height() const { return src.size(); } 26 int find_base(int top, int bot) 27 { 28 for (; i < width(); i++) { 29 for (int k = top; k < bot; k++) { 30 if (src[k][i] != '.') { 31 return k; 32 } 33 } 34 } 35 throw "find_base"; 36 } 37 38 int parse(int top, int bot) 39 { 40 return expr(find_base(top, bot), top, bot); 41 } 42 43 int expr(int base, int top, int bot) 44 { 45 const string& line = src[base]; 46 int r = term(base, top, bot); 47 while (i+2 < width() && line[i] == '.' && (line[i+1] == '+' || line[i+1] == '-') && line[i+2] == '.') { 48 const char op = line[i+1]; 49 i += 3; 50 const int t = term(base, top, bot); 51 if (op == '+') { 52 r = (r + t)%M; 53 } else { 54 r = ((r - t)%M + M)%M; 55 } 56 } 57 return r; 58 } 59 60 int term(int base, int top, int bot) 61 { 62 const string& line = src[base]; 63 int r = factor(base, top, bot); 64 while (i+2 < width() && line[i] == '.' && line[i+1] == '*' && line[i+2] == '.') { 65 i += 3; 66 const int t = factor(base, top, bot); 67 r = (r * t)%M; 68 } 69 return r; 70 } 71 72 int factor(int base, int top, int bot) 73 { 74 const string& line = src[base]; 75 if (line[i] == '-') { 76 if (line[i+1] == '.') { 77 i += 2; 78 const int r = factor(base, top, bot); 79 return (-r + M)%M; 80 } else { 81 const int save = i; 82 const int n = parse(top, base); 83 i = save; 84 const int d = parse(base+1, bot); 85 i = save; 86 while (i < width() && line[i] == '-') { 87 ++i; 88 } 89 return (n * powmod(d, M-2))%M; 90 } 91 } else { 92 return powexpr(base, top, bot); 93 } 94 } 95 96 int powexpr(int base, int top, int bot) 97 { 98 int r = primary(base, top, bot); 99 if (base-1 >= top && i < width() && isdigit(src[base-1][i])) { 100 const int n = src[base-1][i]-'0'; 101 i++; 102 return powmod(r, n); 103 } else { 104 return r; 105 } 106 } 107 108 int primary(int base, int top, int bot) 109 { 110 const string& line = src[base]; 111 if (line[i] == '(' && line[i+1] == '.') { 112 i += 2; 113 const int r = expr(base, top, bot); 114 i += 2; 115 return r; 116 } else { 117 const int n = line[i]-'0'; 118 i++; 119 return n; 120 } 121 } 122 }; 123 124 int main() 125 { 126 int N; 127 while (cin >> N && N != 0) { 128 parser p; 129 p.src.resize(N); 130 for (int i = 0; i < N; i++) { 131 cin >> p.src[i]; 132 } 133 cout << p.parse(0, N) << endl; 134 } 135 return 0; 136 }