如何写出一道大模拟

· · 个人记录

如何写出一道大模拟

答:不知道

接下来会用一道大模拟来举例子,当然你只看加粗的字也行

首先就是要把题给读懂了,一个字也别少读读不懂就多读几遍,直到读懂为止。

while(没读懂)再读一遍;

当然我们还是需要一点审题的技巧的。首先就是要边读题边做记录,在草稿纸或文本文档中将需要做的事情理顺

其次是最好将每个步骤分到不同的函数中去写,这样后期调试/读代码都很方便。

可以按照写出函数的复杂程度来写,一步一步的将思路理顺了。

写完一个函数就验证一下这个函数有没有写对,不然等最后都写完了再调,那可就麻烦死了。

写完以后记得自己多造几组数据,全过了再提交。

接下来用我从某 OJ 上盗过来的题这道题来举个栗子。

首先先整理一下题意:

然后最后对于每一条指令,如果不满足要求就根据题意回显或是输出 INVALID。如果满足条件则输出四行:

第一行固定输出为 gen

第二行输出的是指令中所有形如 XXX.XXX 的文件名。

第三行是输出输出文件的前缀和后缀,如果指令中没有形如 XXX%NUM%.XXX 的东西,则默认为 out.txt

第四行输出所有文件的编号,从小到大,不重复的输出。

好了现在你已经把题都读懂了,可以自己去做题去了,没读懂就再读亿遍,我们(可以)按照由简到繁的顺序来完成程序

第一步先将程序的框架写好:

#include<bits/stdc++.h>
using namespace std;
void zhiling(){
    //为了让代码看起来舒服一点,每条指令用个函数来判断
    string s;
    getline(cin,s);
}
int main(){
    int t;
    cin>>t;
    while(t--){
        zhiling();
    }
}

然后先从最简单的步骤开始写,也就是先写回显、错误和输出函数。

回显和错误都很简单:

void inv(){
    cout<<"INVALID\n";
}
void huixian(string s){
    cout<<"Are you sure: "<<s<<"\n";
}

然后是输出函数:

void out(vector<string>vs,string qz,string hz,vector<int>vi){
    cout<<"gen\n";
    for(auto s:vs)cout<<s<<" ";
    cout<<"\n"<<qz<<" "<<hz<<"\n";
    for(auto s:vi)cout<<s<<" ";
    cout<<"\n";
}

热芝士,顺便把敲烂警钟:endl 比 '\n' 慢很多。

这部分挺简单的吧,接下来正式开始写。

指令中会包含许多的空格,我们可不想要这些空格,而且希望能够将字符串分成许多部分,例如将 XXX.XXX 这类的文件名从字符串中分离出来。所以来写一个拆分字符串的函数:

首先肯定需要用一个 vector 来记录分成那些。

vector<string>fen(string s){
    vector<string>ve={""};
    for(int i=0;i<s.size();i++){
    }
    return ve;
}

在 for 循环里面,肯定先要判断字符串的第 i 位是不是空格:

如果当前 ve 中的最后一个位置不为空串,就 push 进去一个空串,这样就能够将一堆空格的左边和右边的字符串分开。

if(s[i]==' ')
    if(ve.back().size())ve.push_back("");

如果第 i 位是 [,],时,我们要将它们单独分成一个字符串,方便将后面的数字完整的分离出来:

if(s[i]=='['||s[i]==']'||s[i]==','){
    if(ve.back().size())ve.push_back("");
    //如果ve中的最后一个字符串不为空串则需要新开一个字符串来存
    ve.back().push_back(s[i]);
    ve.push_back("");
}

最后就是其它类型的,直接 push 到 ve 最后一个字符串的末尾即可:

ve.back().push_back(s[i]);

现在已经将整条指令拆分完了,但 ve 最后一位有可能是个空串,我们还需要将其删去:

while(ve.size()&&ve.back()=="")ve.pop_back();

温馨提示:写大模拟时,请在能确保 AC 的情况下再进行压行

现在拆分指令的函数就算彻底的完成了,但是你最好用几条指令测试一下拆分出来的和你想要它拆分出来的对不对:

for(auto s:ve)cout<<'"'<<s<<'"'<<'\n';

例如输入 gen xxx.txt [11,22][1,2] 3,那么你的程序就应该输出的是:

"gen"
"xxx.txt"
"["
"11"
","
"22"
"["
"1"
","
"2"
"]"
"3"

如果输出的不是这些那么肯定是哪里写错了。写大模拟不要等到最后把所有的东西都写完了再调试,那样很难调的。

接下来就来写最麻烦的地方了,还是要理清思路再写

首先,如果 ve_i 是左括号,那么在它后面的 4 个字符串必须是 纯数字的,,,纯数字的,],这样才是合法的。我们最好写一个函数用于判断一个字符串是不是纯数字的。后面也会再用到。我们将这个区间中的数字都加入到一个用于记录文件编号的 vector 数组中即可。

然后就是,如果 ve_i 是纯数字的,直接往用来记录文件编号的 vector 数组中 push 进去一个数即可。

如果 ve_i 中包含 %,则判断一下这个字符串是否有且仅有一个 %NUM,且不在第一位。注意一下题目中有条件说了,形如 XXX%NUM%.XXX 的格式只能出现一次。

最后剩下的就是普通的文件名,都用一个 vector 存起来就是了。

这就是这个代码的核心部分需要干的事,写代码的时候注意一些细节就可以了。

好了,现在你已经学会了如何写出一道大模拟了,去拿这道题练练手吧!