当前位置: 首页 > news >正文

解题记录说是 | P3695 CYaRon!语

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

额,作用是进行比较,返回合法与否,为了方便 whileihu 而生。

点击查看代码
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 啦!

http://www.hskmm.com/?act=detail&tid=9995

相关文章:

  • 分享一个极度精简的绿色的 五笔输入法
  • 实用指南:AI推理范式:从CoT到ReAct再到ToT的进化之路
  • sign up - Gon
  • ctfshow web入门 信息搜集
  • 完整教程:数据结构:单链表的应用(力扣算法题)第二章
  • CF2039E Shohag Loves Inversions
  • U522155 板垣 カノエ is WATCHING YOU std
  • ctfshow web
  • 代码随想录算法训练营第三天 | leetcode 203 707 206
  • Codeforces Round 1051 (Div. 2) A~D2
  • 【F#学习】数组:Array
  • CTFWEB姿势总结
  • 规模化加速AI:从用户、开发者到企业的深度策略解析
  • ctfshow 菜狗杯
  • 国际服务器(VPS):泰国、印尼、菲律宾、马来西亚、香港、台湾、新加坡、日本、美国、英国等。
  • 缓存常见问题
  • ctfshow 电子取证
  • Hello,World!
  • 最新IDEA 2025 专业版破解永久破解教程(附资源)intellij IDEA
  • AtCoder ABC423F - Loud Cicada 题解 容斥原理
  • 1756:八皇后
  • 矩阵置零-leetcode
  • 嘉立创常用快捷键
  • 02020402 EF Core基础02-EF Core数据的增删改查
  • conda 无法安装依赖 CondaHTTPError: HTTP 000 CONNECTION FAILED for url: tsinghua tencentaliyun
  • 牛客刷题-Day2
  • 图解支付系统账务系统核心设计 - 智慧园区
  • vulnhub(持续更新)
  • 小爱同学连接电脑进行交互 教程
  • 网络流初步浅谈:EK与Dinic