【NOIP2013普及組P2】表示式求值(NKOJ2500)題解
【NOIP2013普及組P2】表示式求值
Time Limit:10000MS Memory Limit:128000K
Total Submit:37 Accepted:19
Case Time Limit:1000MS
Description
給定一個只包含加法和乘法的算術表示式,請你程式設計計算表示式的值。
Input
輸入僅有一行,為需要你計算的表示式,表示式中只包含數字、加法運算子“+”和乘法運算子“*”,且沒有括號.
所有參與運算的數字均為0到2^31-1之間的整數。輸入資料保證這一行只有0~9、+、*這12種字元。
Output
輸出只有一行,包含一個整數,表示這個表示式的值。注意:當答案長度多於4位時,請只輸出最後4位,前導0不輸出。
Sample Input
【樣例1】
1+1*3+4
【樣例2】
1+1234567890*1
【樣例3】
1+1000000003*1
Sample Output
【樣例1】
8
【樣例2】
7891
【樣例3】
4
Hint
【樣例說明】
樣例1計算的結果為8,直接輸出8。
樣例2計算的結果為1234567891,輸出後4位,即7891。
樣例3計算的結果為1000000004,輸出後4位,即4。
【資料範圍】
對於30%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100;
對於80%的資料,0≤表示式中加法運算子和乘法運算子的總數≤1000;
對於100%的資料,0≤表示式中加法運算子和乘法運算子的總數≤100000。
Source
中綴表示式求值——用兩個棧 sign[] 和 num[] 分別儲存符號和數字。
當讀入的字元是數字的時候:
用 tt 表示當前讀到的單個數字,則 number = number * 10 + tt
當讀入的字元是符號的時候:
1.此時可以保證之前讀入的一個完整數字 number 已經可以放入 num 棧當中了, 即 num[++topn] =number ;並將 number 賦值為 0 ,便於下次正確讀入一個完整數字;
2.
a.)如果當前讀到的運算子優先順序低於或等於前一個(即 sign 棧頂)運算子優先順序,則前面讀到的兩個數(num[topn - 1] 和 num[topn])可以進行運算,並把運算後的結果直接替代到 num[topn - 1] ——舉個例子,對於這個式子 3 * 2 + 1 ,當讀入到加號的時候便可以把式子從 3 * 2 + 變化為 6 + 了;
b.)如果當前讀入的運算子優先順序大於之前讀入的運算子,則正常壓入符號棧 sign 當中;
請注意,當我們這樣完整地一邊讀入一邊處理完一個式子之後,此時的簡化後的式子一定滿足:前面的運算子優先順序小於等於後面(即運算子升序排列)——這是因為如果讀入時一個式子優先順序大於等於後面的運算子,則已經被提前計算並化簡成一個數字,比如 3 * 2 + 1 ,在讀入加號時便把 3 * 2 化為 6 了。
既然此時的式子滿足這樣一個順序(運算子升序排列),我們只要從後往前把式子算一遍就可以得出表示式的值了。
寫到這裡,程式框架已經很清晰了;當然,針對於題目而言自然有一些相應的細節。比如,這道題當中只要求輸出最後 4 位,所以運算過程當中是可以隨時取模 10000(=10^4) 的(實際上也需要這麼做,因為儘管每個數不會超過 2^31 - 1 ,但它們的積或和就不一定了,是很有可能爆 long long int 的)。
最後附上程式碼。
#include <cstdio>
long long int num[100005];
char sign[100005], temp[4];
int lv[100005], signlv[260];
int topn, tops;
long long int number;
long long int f(char s) {
switch (s) {
case '+':
return (num[topn] + num[topn + 1]) % 10000;
case '*':
return (num[topn] * num[topn + 1]) % 10000;
default:
return -1;
}
return -1;
}
void init() {
lv[0] = -1;
signlv['+'] = 1;
signlv['*'] = 2;
return ;
}
void solve() {
char tt;
while ((tt = getchar()) != '\n') {
switch (tt) {
case '+':
case '*': {
num[++topn] = number;
number = 0;
if (lv[tops] < signlv[tt])
++tops;
else
num[--topn] = f(sign[tops]);
sign[tops] = tt;
lv[tops] = signlv[tt];
break;
}
default: {
number = number * 10 + tt - '0';
break;
}
}
}
num[++topn]= number;
while (tops)
num[--topn] = f(sign[tops--]);
return ;
}
void output() {
bool flag = false;
temp[0] = num[1] % 10;
temp[1] = (num[1] /= 10) % 10;
temp[2] = (num[1] /= 10) % 10;
temp[3] = (num[1] /= 10) % 10;
if (!temp[0] && !temp[1] && !temp[2] && !temp[3]) {
putchar('0');
putchar('\n');
return ;
}
if (temp[3] || flag) {
putchar(temp[3] + '0');
flag = true;
}
if (temp[2] || flag) {
putchar(temp[2] + '0');
flag = true;
}
if (temp[1] || flag) {
putchar(temp[1] + '0');
flag = true;
}
if (temp[0] || flag)
putchar(temp[0] + '0');
putchar('\n');
return ;
}
int main() {
init();
solve();
output();
return 0;
}