模拟题的特性
- 题目极长
- 数据极小(无论怎么暴力都能过的那种)
- 实现极其恶心
典型例题
做题思路
先来看一道较为简单的题目:
#include<bits/stdc++.h>
using namespace std;
int n,m,flag=1;
struct Node{
int dir;
char name[10];
}a[100005];
void cl(int &s){
if(s>n) s-=n;
if(s<=0) s+=n;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d %s",&a[i].dir,a[i].name);
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
x+=a[flag].dir;
if(x%2==1){
flag+=y;
cl(flag);
}
else{
flag-=y;
cl(flag);
}
}
printf("%s",a[flag].name);
}
按照题意直接模拟即可。
这里讲这道题的目的是为了介绍模拟题一些比较常用的处理方法:
离线所有询问后处理
这种方法适用于那些操作较复杂,且输入涉及一些字符串及整数的问题,虽然我们边读入边处理也是可行的,但是处理所有输入就比较麻烦,所以我们离线下来处理。
在读入时顺便处理,读入玩后小处理一下即输出。
这种方法适用于操作比较简单,且输入只有少量不对我们的运算有什么影响的字符串,那么边读入边处理就会使我们的代码较为简洁,省去了预处理的过程。
tips:对于一些高难度的模拟题,推荐使用方法
我们再看一道难一点的题目:
这次我们不能单纯按照题意简单模拟,这时,上面提到的法一就十分的适用了。如果你用法二,在读入时处理,可行性也是有的,但是我们需要在判断错误时读入完再退出,就很麻烦。
我们先来跟着题意走,
首先有 组数据。
int t;
cin>>t;
while(t--){
//do something
}
接下来每个程序的第一行包含一个正整数 和一个字符串, 代表程序行数,字符串表示这个程序的复杂度,O(1)表示常数复杂度,O(n^w)表示复杂度为
读入代码如下:
int l;
cin>>l;
string s;
getline(cin,s);
处理有用信息
//输出一下刚才的字符串s,发现开头有一个空格,故我们要讲所有的指针都+1
//例如,本来O(n^w)的n的下标应该为2,但s[0]=' ',故s[3]才是n或者1;
int getfzd(){ //处理本题的时间复杂度
if(s[1][3]=='1') return 0;
int pos=5,num=0;
while(isdigit(s[1][pos])){//我第一次认为w为一位数,WA64分
num=num*10+s[1][pos]-'0';
pos++;
}
return num;
}
继续往下看
接下来 行代表程序中循环结构中的F i x y或者 E。 程序行若以F开头,表示进入一个循环,之后有空格分离的三个字符(串)i x y, 其中 是一个小写字母(保证不为 ),表示新建的变量名, 和 可能是正整数或 ,已知若为正整数则一定小于 。
对于 的情况,我们先提取出里面的 ,将 判断是否重复,再存进一个 表(这里我用 实现),然后用类似读优的方式提取出 。
int getnum1(int x){
int num=0,i,flag=0;
for(i=0;i<s[x].size();i++){
if(!isdigit(s[x][i])){
if(s[x][i]=='n'){
return 1000000;//n远大于100
}
}
while(isdigit(s[x][i])){
flag=1;
num=num*10+s[x][i]-'0';
i++;
}
if(flag) return num;
}
}
int getnum2(int x){
int num=0,i,flag=0;
for(i=0;i<s[x].size();i++){
if(!isdigit(s[x][i])){
if(s[x][i]=='n') {
i++;break;
}
continue;
}
while(isdigit(s[x][i])){
flag=1;
i++;
}
if(flag) break;
}
while(!isdigit(s[x][i])){
if(s[x][i]=='n') return 1000000;
i++;
}
while(i<s[x].size()&&isdigit(s[x][i])){
num=num*10+s[x][i]-'0';
i++;
}
return num;
}
然后如果循环可以进入且后一位是 ,那么我们就增加我们记录的循环次数。
当然,此处要注意一个问题,那就是如果前面的循环没有进入,那么后面的循环即使很大我们也不会去处理,故此处我们用一个 来记录前面的循环是否进入。
int fir=getnum1(i),sec=getnum2(i);
if(fir<=100&&sec==1000000){
s2.push(lstf);
myf+=lstf,maxn=max(maxn,myf);
}
if(fir<=100&&sec<=100&&fir<=sec) s2.push(0);
if(fir==1000000&&sec<=100) s2.push(lstf=0);
if(fir<=100&&sec<=100&&fir>sec) s2.push(lstf=0);
if(fir==1000000&&sec==1000000) s2.push(0);
在处理 的时候,我们将这个循环中记录的 以及循环次数全部更新为上一个循环的值,所以我们用一个后进先出的数据结构——栈来记录。
最后注意细节,本体就拿到满分了。
#include<bits/stdc++.h>
using namespace std;
int T,l;
string s[105];
int getfzd(){
if(s[1][3]=='1') return 0;
int pos=5,num=0;
while(isdigit(s[1][pos])){
num=num*10+s[1][pos]-'0';
pos++;
}
return num;
}
int getnum1(int x){
int num=0,i,flag=0;
for(i=0;i<s[x].size();i++){
if(!isdigit(s[x][i])){
if(s[x][i]=='n'){
return 1000000;
}
}
while(isdigit(s[x][i])){
flag=1;
num=num*10+s[x][i]-'0';
i++;
}
if(flag) return num;
}
}
int getnum2(int x){
int num=0,i,flag=0;
for(i=0;i<s[x].size();i++){
if(!isdigit(s[x][i])){
if(s[x][i]=='n') {
i++;break;
}
continue;
}
while(isdigit(s[x][i])){
flag=1;
i++;
}
if(flag) break;
}
while(!isdigit(s[x][i])){
if(s[x][i]=='n') return 1000000;
i++;
}
while(i<s[x].size()&&isdigit(s[x][i])){
num=num*10+s[x][i]-'0';
i++;
}
return num;
}
int main(){
cin>>T;
while(T--){
cin>>l;
for(int i=1;i<=l+1;i++){
getline(cin,s[i]);
}
int fzd=getfzd(),fnum=0,flag=0,myf=0,maxn=0,lstf=1;
map<char,int> mp;
stack<char> S;
stack<int> s2;
s2.push(1);
for(int i=2;i<=l+1;i++){
if(s[i][0]=='F'){
fnum++;
char ch=s[i][2];
if(mp[ch]){
puts("ERR");
flag=1;
break;
}
mp[ch]=1;
S.push(ch);
int fir=getnum1(i),sec=getnum2(i);
if(fir<=100&&sec==1000000){
s2.push(lstf);
myf+=lstf,maxn=max(maxn,myf);
}
if(fir<=100&&sec<=100&&fir<=sec) s2.push(0);
if(fir==1000000&&sec<=100) s2.push(lstf=0);
if(fir<=100&&sec<=100&&fir>sec) s2.push(lstf=0);
if(fir==1000000&&sec==1000000) s2.push(0);
}
if(s[i][0]=='E'){
if(fnum==0){
flag=1;
puts("ERR");
break;
}
fnum--;
char ch=S.top();
S.pop();
mp[ch]=0;
myf-=s2.top();
s2.pop();
lstf=s2.top();
}
}
if(flag) continue;
if(fnum){
puts("ERR");
continue;
}
if(maxn!=fzd){
puts("No");
}
else puts("Yes");
}
}