link
起因
闲的没事找模拟做,发现这个部分分的档次很多,而且好想挺好做,就做了。
是分着部分分做的,而且完全就是那种苦(封装各种实现)尽甘(飞速写完 ihu
hor
while
)来的感觉,很爽的。
code goes first
点击查看代码
// code by 樓影沫瞬_Hz17
#include <bits/stdc++.h>
using namespace std;#define getc() getchar_unlocked()
#define putc(a) putchar_unlocked(a)
#define en_ putc('\n')
#define e_ putc(' ')using pii = pair<int, int>;template<class T> inline void out(T n) {if(n < 0) putc('-'), n = -n;if(n > 9) out(n / 10);putc(n % 10 + '0');
}const int N = 5e5 + 10;string cmd;
string get_num(uint &i);
void code_start(uint &i, int up);map<string, int> mp;inline void to__(uint &i) {while(cmd[i] != ' ' and cmd[i] != -1 and cmd[i] != '\n') i ++;
}inline void pass(uint &i) {while((cmd[i] == ' ' || cmd[i] == '\n' || cmd[i] == '\t') and cmd[i] != -1) i ++;
}inline string get_str(uint &i) {string tmp = "";pass(i);if(cmd[i] == '+' || cmd[i] == '-') {tmp += cmd[i]; i++;return tmp;}while(cmd[i] != ' ' and cmd[i] != ':' and cmd[i] != '\n' and cmd[i] != -1 and cmd[i] != ',' and cmd[i] != '+' and cmd[i] != '-') {tmp.push_back(cmd[i]);i ++;}return tmp;
}inline int in(uint &i) { int n = 0; char p = cmd[i ++];while (!isdigit(p) and p != '-') p = cmd[i ++];bool f = p == '-' ? p = cmd[i ++] : 0;do n = n * 10 + (p ^ 48), p = cmd[i ++];while (isdigit(p) and cmd[i] != -1);i --;return f ? -n : n;
}inline int add(vector<pair<string, int> > s) {int tmp = 0;for(pair<string, int> v : s) {if(v.first == "") {tmp += v.second;continue;}tmp += mp[v.first] * v.second;}return tmp;
}inline vector<pair<string, int>> formula(uint & i) {vector<pair<string, int> > k;int fu = 1;while(cmd[i] != '\n' and cmd[i] != -1 and cmd[i] != ']' and cmd[i] != ',') {int j = i;string h = get_str(i);if(h == "+") fu = 1;else if(h == "-") fu = -1;else i = j;pass(i);if(isdigit(cmd[i])) {int var = in(i);k.push_back({"",var * fu});}else h = get_num(i);k.push_back({h, fu});}return k;
}inline int calc(uint &i) { return add(formula(i)); }inline string get_num(uint &i) {pass(i);string tm = "";int aaa = 0;while(cmd[i] <= 'z' and cmd[i] >= 'a') tm += cmd[i ++];if(cmd[i] == '[') {i ++;aaa = calc(i);pass(i);i ++;return tm + '[' + to_string(aaa) + ']';} return tm;
}inline int get_r(uint ff) {int cl = 0;for(int i = ff; i < cmd.size(); i ++) {if(cmd[i] == '{') cl ++;if(cmd[i] == '}') {cl --;if(cl == -1) return i;}}
}inline bool pan(int val1, int val2, int p) {switch (p) {case 1: return val1 == val2; break;case 2: return val1 != val2; break;case 3: return val1 < val2; break;case 4: return val1 > val2; break;case 5: return val1 <= val2; break;case 6: return val1 >= val2; break;}
}inline void var(uint &i) {while(cmd[i] != '}') i ++;
}inline void ihu(uint &i) {int p;string pp = get_str(i);switch(pp[0] + pp[1]) {case 'e' + 'q': p = 1; break;case 'n' + 'e': p = 2; break;case 'l' + 't': p = 3; break;case 'g' + 't': p = 4; break;case 'l' + 'e': p = 5; break;case 'g' + 'e': p = 6; break;} i ++;pass(i);vector<pair<string, int>> fi = formula(i);i ++;pass(i);vector<pair<string, int>> se = formula(i);int up = get_r(i);if(pan(add(fi), add(se), p)) {uint j = i + 1;code_start(j, up);}i = up;
}inline void whil(uint &i) {int p;string pp = get_str(i);switch(pp[0] + pp[1]) {case 'e' + 'q': p = 1; break;case 'n' + 'e': p = 2; break;case 'l' + 't': p = 3; break;case 'g' + 't': p = 4; break;case 'l' + 'e': p = 5; break;case 'g' + 'e': p = 6; break;} i ++;pass(i);vector<pair<string, int>> fi = formula(i);i ++;pass(i);vector<pair<string, int>> se = formula(i);int up = get_r(i);while(pan(add(fi), add(se), p)) {uint j = i + 1;code_start(j, up);}i = up;
}inline void hor(uint &i) {i ++;pass(i);string fi = get_num(i);i ++;pass(i);vector<pair<string, int>> se = formula(i);i ++;pass(i);vector<pair<string, int>> th = formula(i);int up = get_r(i);for(mp[fi] = add(se); pan(mp[fi], add(th), 5); mp[fi] ++) {uint j = i + 1;code_start(j, up);}mp[fi] --;i = up;
}inline void code_start(uint &i, int up) {for(; i <= up;) {char op = cmd[i ++];if(op == '{') {while(op != 'v' and op != 'i' and op != 'h' and op != 'w') op = cmd[i ++];to__(i);if(op == 'v') var(i);if(op == 'i') ihu(i); if(op == 'w') whil(i);if(op == 'h') hor(i);}if(op == ':') {op = cmd[i ++];if(op == 's') {i += 2;string t = get_num(i);i ++;int v = calc(i);mp[t] = v;}else {i += 5;out(calc(i)); e_;}}}
}signed main() {#ifndef ONLINE_JUDGEfreopen("i.ru", "r", stdin);freopen("o", "w", stdout);#endifchar c;while(1) {c = getc();if(c == '#') {while(c != '\n') c = getc();cmd += c;}else cmd.push_back(c);if(c == -1) break;}// cout << cmd;uint i = 0;code_start(i, cmd.size() - 1);
}
// 星間~ 干渉~ 融解~ 輪迴~ 邂逅~ 再生~ ララバイ~
这里面本来有很多刻意的错拼(笑),挺有意思的。
讲解
首先我们显然发现注释是没有用的,所以略过注释,并且发现我们先读入所有的东西再处理会让ihu
hor
while
等变得更好处理,所以我们一次性读到 cmd
里面,这很好。
点击查看代码
while(1) {c = getc();if(c == '#') {while(c != '\n') c = getc();cmd += c;}else cmd.push_back(c);if(c == -1) break;}
然后我们一个一个看操作们。
基础函数们
to__
后面的 __
是空格的意思,作用为跳到下一个空格等空白字符处。
点击查看代码
inline void to__(uint &i) {while(cmd[i] != ' ' and cmd[i] != -1 and cmd[i] != '\n') i ++;
}
pass
含义为跳过空格类的无用字符。如 \t
\n
之类的。
点击查看代码
inline void pass(uint &i) {while((cmd[i] == ' ' || cmd[i] == '\n' || cmd[i] == '\t') and cmd[i] != -1) i ++;
}
get_str
作用为返回一定量的合法字符,有很多的边界,为\n
-1
\t
:
+
-
,特殊的有返回符号(+
-
)就只返回单个的符号。
点击查看代码
inline string get_str(uint &i) {string tmp = "";pass(i);if(cmd[i] == '+' || cmd[i] == '-') {tmp += cmd[i]; i++;return tmp;}while(cmd[i] != ' ' and cmd[i] != ':' and cmd[i] != '\n' and cmd[i] != -1 and cmd[i] != ',' and cmd[i] != '+' and cmd[i] != '-') {tmp.push_back(cmd[i]);i ++;}return tmp;
}
in
魔改快读,作用为返回下一个合法的数字。
点击查看代码
inline int in(uint &i) { int n = 0; char p = cmd[i ++];while (!isdigit(p) and p != '-') p = cmd[i ++];bool f = p == '-' ? p = cmd[i ++] : 0;do n = n * 10 + (p ^ 48), p = cmd[i ++];while (isdigit(p) and cmd[i] != -1);i --;return f ? -n : n;
}
pan
额,作用是进行比较,返回合法与否,为了方便 while
和 ihu
而生。
点击查看代码
inline bool pan(int val1, int val2, int p) {switch (p) {case 1: return val1 == val2; break;case 2: return val1 != val2; break;case 3: return val1 < val2; break;case 4: return val1 > val2; break;case 5: return val1 <= val2; break;case 6: return val1 >= val2; break;}
}
get_r
效果是返回第一个没有匹配的 }
,作用显然,是在 ihu
while
hor
里作为边界的。
inline int get_r(uint ff) {int cl = 0;for(int i = ff; i < cmd.size(); i ++) {if(cmd[i] == '{') cl ++;if(cmd[i] == '}') {cl --;if(cl == -1) return i;}}
}
二级函数们
首先是算数的。
formula
得到一个公式的表达,并返回整个公式,非常有用。
实现不算很难,主要是分辨符号和数字和变量。
注意边界条件,主要是由于它的几个不同使用条件。
点击查看代码
inline vector<pair<string, int>> formula(uint & i) {vector<pair<string, int> > k;int fu = 1;while(cmd[i] != '\n' and cmd[i] != -1 and cmd[i] != ']' and cmd[i] != ',') {int j = i;string h = get_str(i);if(h == "+") fu = 1;else if(h == "-") fu = -1;else i = j;pass(i);if(isdigit(cmd[i])) {int var = in(i);k.push_back({"",var * fu});}else h = get_num(i);k.push_back({h, fu});}return k;
}
add
一个比较有用的函数,有用是因为 formula
有用。
效果为计算刚才得到的算式。
点击查看代码
inline int add(vector<pair<string, int> > s) {int tmp = 0;for(pair<string, int> v : s) {if(v.first == "") {tmp += v.second;continue;}tmp += mp[v.first] * v.second;}return tmp;
}
顺便附上 calc
,这是一个便于计算只使用一次的函数而生的。
inline int calc(uint &i) { return add(formula(i)); }
后面是其他的二级函数。
get_num
如果你仔细看了 formula
函数就会发现这个东西,它的作用是尝试读入一个合法的变量(并翻译),如果是数字就会直接返回不会读入,也是很有用的函数,其中计算数组下标导致它和 formula
相互调用......
点击查看代码
inline string get_num(uint &i) {pass(i);string tm = "";int aaa = 0;while(cmd[i] <= 'z' and cmd[i] >= 'a') tm += cmd[i ++];if(cmd[i] == '[') {i ++;aaa = calc(i);pass(i);i ++;return tm + '[' + to_string(aaa) + ']';} return tm;
}
几个实现向的函数
没错!!!苦尽甘来!!!
有了前面的铺垫,接下来的函数都非常好实现了。
code_start
表示将程序位于 \([i,up]\) 的代码运行,作用是链接其他的函数和方便循环。
点击查看代码
inline void code_start(uint &i, int up) {for(; i <= up;) {char op = cmd[i ++];if(op == '{') {while(op != 'v' and op != 'i' and op != 'h' and op != 'w') op = cmd[i ++];to__(i);if(op == 'v') var(i);if(op == 'i') ihu(i); if(op == 'w') whil(i);if(op == 'h') hor(i);}if(op == ':') {op = cmd[i ++];if(op == 's') {i += 2;string t = get_num(i);i ++;int v = calc(i);mp[t] = v;}else {i += 5;out(calc(i)); e_;}}}
}
var
美妙的定义,你发现这个根本不用实现。其实用一次 get_r
就行,不过给足尊重,写个函数。
点击查看代码
inline void var(uint &i) {while(cmd[i] != '}') i ++;
}
change
求出前后两个变量然后更改就行,实现在 code_start
里面。
out
求出表达式的值然后输出,实现在 code_start
里面。
ihu
首先求出符号类型,再得到两个表达式,比较并运行就行。
点击查看代码
inline void ihu(uint &i) {int p;string pp = get_str(i);switch(pp[0] + pp[1]) {case 'e' + 'q': p = 1; break;case 'n' + 'e': p = 2; break;case 'l' + 't': p = 3; break;case 'g' + 't': p = 4; break;case 'l' + 'e': p = 5; break;case 'g' + 'e': p = 6; break;} i ++;pass(i);vector<pair<string, int>> fi = formula(i);i ++;pass(i);vector<pair<string, int>> se = formula(i);int up = get_r(i);if(pan(add(fi), add(se), p)) {uint j = i + 1;code_start(j, up);}i = up;
}
whil
和上一个一模一样,不过是把 if
换成了 while
。
点击查看代码
inline void whil(uint &i) {int p;string pp = get_str(i);switch(pp[0] + pp[1]) {case 'e' + 'q': p = 1; break;case 'n' + 'e': p = 2; break;case 'l' + 't': p = 3; break;case 'g' + 't': p = 4; break;case 'l' + 'e': p = 5; break;case 'g' + 'e': p = 6; break;} i ++;pass(i);vector<pair<string, int>> fi = formula(i);i ++;pass(i);vector<pair<string, int>> se = formula(i);int up = get_r(i);while(pan(add(fi), add(se), p)) {uint j = i + 1;code_start(j, up);}i = up;
}
hor
这个甚至还要好实现些,你连符号都不用读入了,直接读入一个变量两个表达式,然后 for
就完了。
点击查看代码
inline void hor(uint &i) {i ++;pass(i);string fi = get_num(i);i ++;pass(i);vector<pair<string, int>> se = formula(i);i ++;pass(i);vector<pair<string, int>> th = formula(i);int up = get_r(i);for(mp[fi] = add(se); pan(mp[fi], add(th), 5); mp[fi] ++) {uint j = i + 1;code_start(j, up);}mp[fi] --;i = up;
}
然后呢?
你就 AC 啦!