社区讨论

高二学生,CSPS 初赛在即,求各位大佬提点建议!

灌水区参与者 12已保存回复 12

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
12 条
当前快照
1 份
快照标识符
@mhj9yoa1
此快照首次捕获于
2025/11/03 23:08
4 个月前
此快照最后确认于
2025/11/04 06:03
4 个月前
查看原帖
各位大佬好,我是一名高二学生,目前正在学习信息学竞赛,但即将到来的 CSP-S 初赛让我非常焦虑,感觉自己可能过不了初赛,特来求助!
目前我的情况是:
  1. 无法理解题目中常出现的中文字符,如“彁”“槞”等复杂的汉字我一般看不懂。
  2. 无法理解题目中基础的数学符号,如 cosnxdx={i=0m(1)i(mi)2i+1sin2i+1x+C1,n=2m+1(2m1)!!x(2m)!!+sinxi=1m(2m2i)!!(2m1)!!sin2m2i+1x(2m)!!(2m2i+1)!!+C2,n=2m\int \cos^nx\mathrm dx= \begin{cases} \sum_{i=0}\limits^m(-1)^i\frac{\binom mi}{2i+1}\sin^{2i+1}x+C_1,& n=2m+1\\ \dfrac{(2m-1)!!x}{(2m)!!}+\sin x\sum\limits_{i=1}^m\dfrac{(2m-2i)!!(2m-1)!!\sin^{2m-2i+1}x}{(2m)!!(2m-2i+1)!!}+C2,& n=2m \end{cases} 等基础公式无法理解。
  3. 看不懂一些简单易懂的代码,如 P11738 的一篇题解中的代码我就没看懂,大概是这样的: CPP
     #include <algorithm>
     #include <cctype>
     #include <cmath>
     #include <cstdio>
     #include <cstring>
     #include <memory>
     #include <vector>
     #include <string>
     using namespace std;
    
     using u8 = unsigned char;
     using i16 = short;
     using u16 = unsigned short;
     using i32 = int;
     using u32 = unsigned int;
     using i64 = long long;
     using u64 = unsigned long long;
    
     struct Reader {
       char ch;
       Reader(bool) {}
       Reader() { ch = getchar(); }
       char seek() { return ch; }
       void skip() { ch = getchar(); }
       bool eof() { return ch == EOF; }
       void read(char &c) { c = seek(); skip(); }
       char read() {  char res; return read(res), res; }
     } reader(false);
    
     int input_n, input_a[512], input_cur;
    
     enum TokenType {
       Reserved = 1, Number, Symbol, Name, Eof
     };
     enum ReservedType {
       Error = 0, Using, Int, If, Else, For, While, Return, Cin, Cout, Endl
     };
     enum SymbolType {
       ERROR = 0, HASHTAG, LPAREN, RPAREN, LBRACKET, RBRACKET, LCURLY, RCURLY,
       OR, XOR, AND, NOT, EQ, NE, LT, GT, LE, GE, ADD, SUB, MUL, DIV, MOD, NEG, SHL, SHR,
       SEMICOLON, COMMA, DOT, ASSIGN
     };
     enum InstructionType {
       _LEA, _LEAP, _IMM, _JMP, _JSR, _BZ, _BNZ, _ENT, _ADJ, _LEV, _LI, _SI, _PSH,
       _OR, _XOR, _AND, _NOT, _EQ, _NE, _LT, _GT, _LE, _GE,
       _ADD, _SUB, _MUL, _DIV, _MOD, _NEG, _SHL, _SHR, _CIN, _COUT, _PCHR, _EXIT
     };
    
    
     namespace VM {
     const int MEM_SIZE = 1 << 22;
     const int BYTE_CODE_LENGTH = 1 << 12;
     i64 mem[MEM_SIZE];
     i64 bytecode[BYTE_CODE_LENGTH];
    
     int run(i64 start) {
       i64 *pc = (i64*)start, *sp = mem + MEM_SIZE, *bp = sp, ax, tmp;
       // finally execute _PSH and _EXIT by modifying pc
       *--sp = _EXIT;
       *--sp = _PSH;
       tmp = (i64)sp;
       *--sp = tmp;
    
       while (1) {
         i64 ins = *pc++;
         switch (ins) {
         case _LEA: ax = (i64)(bp + *pc++); break;
         case _LEAP: tmp = ax * (*pc++); ax = (*sp++) + tmp; break;
         case _IMM: ax = *pc++; break;
         case _JMP: pc = (i64*)*pc; break;
         case _JSR: *--sp = (i64)(pc + 1); pc = (i64*)(*pc); break;
         case _BZ: pc = ax ? pc + 1 : (i64*)(*pc); break;
         case _BNZ: pc = ax ? (i64*)(*pc) : pc + 1; break;
         case _ENT: *--sp = (i64)bp; bp = sp; break;
         case _ADJ: if (*pc < 0) memset(sp + *pc, 0, sizeof(i64) * -(*pc)); sp = sp + *pc++; break;
         case _LEV: sp = bp; bp = (i64*)*sp++; pc = (i64*)*sp++; break;
         case _LI: ax = *(i64*)ax; break;
         case _SI: *(i64*)*sp++ = ax; break;
         case _PSH: *--sp = ax; break;
         case _OR: ax = *sp++ || ax; break;
         case _XOR: ax = bool(*sp++) ^ bool(ax); break;
         case _AND: ax = *sp++ && ax; break;
         case _NOT: ax = !ax; break;
         case _EQ: ax = *sp++ == ax; break;
         case _NE: ax = *sp++ != ax; break;
         case _LT: ax = *sp++ < ax; break;
         case _GT: ax = *sp++ > ax; break;
         case _LE: ax = *sp++ <= ax; break;
         case _GE: ax = *sp++ >= ax; break;
         case _ADD: ax = *sp++ + ax; break;
         case _SUB: ax = *sp++ - ax; break;
         case _MUL: ax = *sp++ * ax; break;
         case _DIV: ax = *sp++ / ax; break;
         case _MOD: ax = *sp++ % ax; break;
         case _NEG: ax = -ax; break;
         case _SHL: printf("%d", (int)ax); sp++; break;
         case _SHR: *(i64*)ax = input_a[input_cur++]; sp++; break;
         case _PCHR: putchar(ax); sp++; break;
         case _EXIT: return (int)ax;
         }
       }
     }
     };
    
     const u32 ID_HASH_LENGTH = 1 << 12;
     char* id_hash[ID_HASH_LENGTH];
     u32 easy_hash(const char *str) {
       u32 res = 0;
       while (*str != '\0')
         res = res * 331 + *(str ++);
       return res;
     }
     u32 insert_id(const char *str) {
       u32 hsh = easy_hash(str) & (ID_HASH_LENGTH - 1);
       while (id_hash[hsh] != nullptr && strcmp(id_hash[hsh], str))
         hsh = (hsh + 1) & (ID_HASH_LENGTH - 1);
       if (id_hash[hsh] == nullptr) {
         char* strr = new char[strlen(str) + 1];
         strcpy(strr, str);
         id_hash[hsh] = strr;
       }
       return hsh;
     }
    
     namespace TokenFlow {
     template <typename T>
     struct Match {
       const static int MAX_NODE = 128;
       u8 transition[MAX_NODE][256];
       T info[MAX_NODE];
       u8 cnt;
       Match(const vector<pair<const char*, T>> &vec) {
         cnt = 0;
         for (auto &ele: vec) {
           const char *ptr = ele.first;
           u8 cur = 0;
           while (*ptr != '\0') {
             u8 &nxt = transition[cur][(u8)(*(ptr ++))];
             if (nxt == 0) nxt = ++ cnt;
             cur = nxt;
           }
           info[cur] = ele.second;
         }
       }
       T readFromReader() const {
         u8 cur = 0, temp = 0;
         while ((temp = transition[cur][(u8)reader.seek()]))
           cur = temp, reader.skip();
         return info[cur];
       }
       template <typename T2>
       T readFromStr(T2 str) const {
         u8 cur = 0, temp = 0;
         while (*str != '\0') {
           temp = transition[cur][(u8)(*(str ++))];
           if (temp == 0) return info[0];
           cur = temp;
         }
         return info[cur];
       }
     };
    
     const Match<ReservedType> resMatch(vector<pair<const char*, ReservedType>>{
       {"using", Using}, {"int", Int}, {"for", For}, {"while", While}, {"if", If},
       {"else", Else}, {"cin", Cin}, {"cout", Cout}, {"endl", Endl}, {"return", Return}
     });
     const Match<SymbolType> symMatch(vector<pair<const char*, SymbolType>>{
       {"+", ADD}, {"-", SUB}, {"*", MUL}, {"/", DIV}, {"%", MOD}, {"^", XOR}, {"#", HASHTAG},
       {"==", EQ}, {">", GT}, {"<", LT}, {">=", GE}, {"<=", LE}, {"!=", NE}, {"&&", AND}, {"||", OR}, {"!", NOT},
       {"(", LPAREN}, {")", RPAREN}, {"[", LBRACKET}, {"]", RBRACKET}, {"{", LCURLY}, {"}", RCURLY},
       {";", SEMICOLON}, {",", COMMA}, {".", DOT}, {"=", ASSIGN}, {"<<", SHL}, {">>", SHR}
     });
    
     struct Token {
       TokenType type;
       union {
         ReservedType rtype;
         int num;
         SymbolType stype;
         u32 id;
       };
       Token(TokenType type): type(type) {}
       Token(ReservedType rtype): type(Reserved), rtype(rtype) {}
       Token(int num): type(Number), num(num) {}
       Token(SymbolType stype): type(Symbol), stype(stype) {}
       Token(u32 id): type(Name), id(id) {}
       bool operator == (const Token &tk) const {
         if (type != tk.type)
           return false;
         if (type == Reserved)
           return rtype == tk.rtype;
         if (type == Symbol)
           return stype == tk.stype;
         return true;
       }
       bool operator != (const Token &tk) const {
         return !operator==(tk);
       }
     };
    
     Token __current(Eof);
     void read_next_token() {
       while (isspace(reader.seek()))
         reader.skip();
       if (reader.eof())
         __current = Eof;
       else if (isdigit(reader.seek())) {
         int num = 0;
         while (isdigit(reader.seek()))
           num = num * 10 + (reader.read() - '0');
         __current = num;
       }
       else if (isalpha(reader.seek()) || reader.seek() == '_') {
         string str = "";
         while (isalnum(reader.seek()) || reader.seek() == '_')
           str += reader.read();
         auto tp = resMatch.readFromStr(str.c_str());
         if (tp == Error)
           __current = insert_id(str.c_str());
         else if (tp == Using) {
           while (!reader.eof() && reader.seek() != '\n')  reader.skip();
           read_next_token();
           return;
         }
         else __current = tp;
       }
       else {
         auto tp = symMatch.readFromReader();
         if (tp == HASHTAG) {
           while (!reader.eof() && reader.seek() != '\n')  reader.skip();
           read_next_token();
         }
         else __current = tp;
       }
     }
     };
    
     const TokenFlow::Token& tk() { return TokenFlow::__current; }
     void nxt() { TokenFlow::read_next_token(); }
    
     // declare => sizes of array
     int* declare[ID_HASH_LENGTH];
     i64 address[ID_HASH_LENGTH];
     bool global[ID_HASH_LENGTH];
     int SINGLE_VAR[1] = {1};
    
     int* get_array_def_params() {
       vector<int> res;
       while (tk() == LBRACKET) {
         nxt();
         res.push_back(tk().num); 
         nxt(); nxt();
       }
       res.push_back(1);
       for (int i = (int)res.size() - 2; i >= 0; i --)
         res[i] *= res[i + 1];
       int *p = new int[res.size()];
       for (int i = 0; i < (int)res.size(); i ++)
         p[i] = res[i];
       return p;
     }
    
     i64 *ptr = VM::bytecode;
     int stk_tp = 0;
     struct RecoverVar {
       vector<tuple<u32, int, bool, int*>> rec;
       void cover(u32 i, int loc, int* arr = SINGLE_VAR) {
         rec.push_back({i, address[i], global[i], declare[i]});
         address[i] = loc;
         declare[i] = arr;
         global[i] = false;
       }
       void recover(int params = 0) {
         int U = -params;
         for (auto &ele: rec) {
           u32 id = get<0>(ele);
           U += declare[id][0];
           address[id] = get<1>(ele);
           global[id] = get<2>(ele);
           declare[id] = get<3>(ele);
         }
         if (U != 0)
           *ptr++ = _ADJ, *ptr++ = U, stk_tp += U;
       }
     };
    
     int precedence(SymbolType s) {
       switch (s) {
       case SHL: case SHR: return 1;
       case ASSIGN: return 2;
       case OR: return 3;
       case AND: return 4;
       case XOR: return 5;
       case EQ: case NE: return 6;
       case LE: case GE: case LT: case GT: return 7;
       case ADD: case SUB: return 8;
       case MUL: case DIV: case MOD: return 9;
       case NEG: case NOT: return 10;
       default: return 0;
       }
     }
    
     void get_expr();
     bool nxt_endl = false;
     u32 syscall_putchar;
     void get_unit() {
       if (tk() == LPAREN)
         nxt(), get_expr(), nxt();
       else if (tk().type == Name) {
         u32 name = tk().id;
         nxt();
         if (tk() == LPAREN) {
           nxt();
           int num = 0;
           while (tk() != RPAREN) {
             if (num) nxt();
             ++ num; get_expr(); *ptr++ = _PSH;
           }
           if (name == syscall_putchar)
             *ptr++ = _PCHR;
           else {
             *ptr++ = _JSR; *ptr++ = address[name];
             if (num) *ptr++ = _ADJ, *ptr++ = num;
           }
           nxt();
         }
         else {
           if (global[name])
             *ptr++ = _IMM, *ptr++ = (i64)(VM::mem) + address[name] * sizeof(i64);
           else
             *ptr++ = _LEA, *ptr++ = address[name];
           int num = 0;
           while (tk() == LBRACKET) {
             *ptr++ = _PSH;
             nxt(); get_expr(); nxt();
             *ptr++ = _LEAP; *ptr++ = declare[name][++ num] * sizeof(i64);
           }
           *ptr++ = _LI;
         }
       }
       else if (tk().type == Number)
         *ptr++ = _IMM, *ptr++ = tk().num, nxt();
       else if (tk() == Endl)
         nxt_endl = true, *ptr++ = _IMM, *ptr++ = 10, nxt();
       else
         nxt(); // cin & cout
     }
    
     void get_expr() {
       vector<SymbolType> stk;
       int state = 0, temp = 0, temp2 = 0;
       if (tk().type == Name) {
         get_unit();
         if (tk() == ASSIGN) {
           // discard LI and cover
           *(ptr - 1) = _PSH; nxt();
           get_expr(); *ptr++ = _SI;
           return;
         }
         state = 1;
       }
    
       #define pop() {\
         if (nxt_endl)\
           *ptr++ = _PCHR, nxt_endl = false;\
         else if (stk.back() == SHR)\
           *(ptr - 1) = _SHR;\
         else\
           *ptr++ = stk.back() - OR + _OR;\
         stk.pop_back();\
       }
       while (1) {
         if (state == 0) {
           if (tk() == NOT) stk.push_back(NOT), nxt();
           else if (tk() == SUB) stk.push_back(NEG), nxt();
           else if (tk() == ADD) nxt();
           else get_unit(), state = 1;
         }
         else {
           if (tk().type == Symbol && (temp = precedence(tk().stype))) {
             while (!stk.empty() && (temp2 = precedence(stk.back())) >= temp)
               pop();
             stk.push_back(tk().stype); nxt();
             *ptr++ = _PSH; state = 0;
           }
           else break;
         }
       }
       while (!stk.empty())
         pop();
     }
    
     RecoverVar rv;
    
     void get_stmt();
    
     void get_stmts() {
       RecoverVar nrv;
       swap(rv, nrv);
       while (tk() != RCURLY)
         get_stmt();
       swap(rv, nrv);
       nrv.recover();
     }
    
     void get_basic_stmt() {
       if (tk() == Int) {
         int o = 0;
         do {
           nxt(); u32 name = tk().id; nxt();
           int *v = get_array_def_params();
           o -= v[0]; stk_tp -= v[0];
           rv.cover(name, stk_tp, v);
         } while (tk() == COMMA);
         *ptr++ = _ADJ; *ptr++ = o;
       }
       else get_expr();
     }
    
     void get_stmt() {
       if (tk() == SEMICOLON)
         nxt();
       else if (tk() == LCURLY)
         nxt(), get_stmts(), nxt();
       else if (tk() == If) {
         nxt(); nxt(); get_expr(); nxt();
         *ptr++ = _BZ;
         i64 *step_ptr = ptr++;
         get_stmt();
         if (tk() == Else) {
           *ptr++ = _JMP;
           i64 *end_ptr = ptr++;
           *step_ptr = (i64)ptr;
           nxt(); get_stmt();
           *end_ptr = (i64)ptr;
         }
         else
           *step_ptr = (i64)ptr;
       }
       else if (tk() == For) {
         RecoverVar nrv;
         swap(rv, nrv);
         nxt(); // for
         nxt(); // (
         if (tk() != SEMICOLON) get_basic_stmt(); nxt();
         i64 start_ptr = (i64)ptr;
         if (tk() == SEMICOLON) *ptr++ = _IMM, *ptr++ = 1;
         else get_expr();
         *ptr++ = _BNZ;
         i64 *stmt_ptr = ptr++;
         *ptr++ = _JMP;
         i64 *end_ptr = ptr++;
         nxt(); // ;
         i64 effect_ptr = (i64)ptr;
         if (tk() != RPAREN) get_basic_stmt();
         nxt();
         *ptr++ = _JMP; *ptr++ = start_ptr;
         *stmt_ptr = (i64)ptr;
         get_stmt();
         *ptr++ = _JMP; *ptr++ = effect_ptr;
         *end_ptr = (i64)ptr;
         swap(rv, nrv);
         nrv.recover();
       }
       else if (tk() == While) {
         nxt(); nxt();
         i64 start_ptr = (i64)ptr;
         get_expr(); nxt();
         *ptr++ = _BZ;
         i64 *end_ptr = ptr ++;
         get_stmt();
         *ptr++ = _JMP; *ptr++ = start_ptr;
         *end_ptr = (i64)ptr;
       }
       else if (tk() == Return) {
         nxt(); get_expr(); nxt();
         *ptr++ = _LEV;
       }
       else {
         get_basic_stmt();
         nxt();
       }
     }
    
     void get_func(u32 name) {
       address[name] = (i64)ptr;
       global[name] = true;
       *ptr++ = _ENT;
       nxt();
       RecoverVar nrv;
       vector<u32> params;
       while (tk() != RPAREN) {
         if (!params.empty()) nxt();
         nxt(); params.push_back(tk().id); nxt();
       }
       nxt();
       int n = params.size();
       for (int i = 0; i < n; i ++)
         nrv.cover(params[i], n + 1 - i);
       swap(rv, nrv);
       get_stmt();
       *ptr++ = _IMM;
       *ptr++ = 0;
       *ptr++ = _LEV;
       swap(rv, nrv);
       nrv.recover(n);
     }
    
     void get_func_and_var() {
       int bss = 0;
       while (tk() != Eof) {
         nxt(); // int
         u32 name = tk().id;
         nxt(); // name
         if (tk() == LPAREN)
           get_func(name);
         else {
           // var
           declare[name] = get_array_def_params();
           address[name] = bss;
           bss += declare[name][0];
           global[name] = true;
           while (tk() == COMMA) { 
             nxt(); name = tk().id; nxt();
             declare[name] = get_array_def_params();
             address[name] = bss;
             bss += declare[name][0];
             global[name] = true;
           }
           nxt();
         }
       }
     }
    
     void rint(int &x) {
       while (!isdigit(reader.seek()))
         reader.skip();
       while(isdigit(reader.seek()))
         x = x * 10 + (reader.read() ^ 48);
     }
    
     int main() {
       reader = Reader();
       rint(input_n);
       for (int i = 0; i < input_n; i ++)
         rint(input_a[i]);
       syscall_putchar = insert_id("putchar");
       u32 syscall_main = insert_id("main");
       nxt(); get_func_and_var();
       VM::run(address[syscall_main]);
       return 0;
     }
    
    P.S. 感谢 tiger2005 的代码
我已经做了一些往年的初赛题目,但正确率不高,尤其是时间紧张时看不懂汉字。距离初赛时间不多了,想请教大家:
  1. 如何才能快速增进自己的语文水平,让我能读懂基础的句子啊?
  2. 如何才能快速增进自己的数学水平,让我能看懂基础的公式啊?
  3. 如何才能快速增进自己的编程水平,让我能看懂基础的代码啊?
真的很想通过初赛,争取在复赛中更进一步,但现在感觉有点迷茫。希望各位大佬能指点一二,非常感谢!
(如果愿意的话,也可以分享一些易错点或常见坑,谢谢大家!)

回复

12 条回复,欢迎继续交流。

正在加载回复...