关于模拟的那些事er

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/wljoi/article/details/102578873

模拟题的特性

  • 题目极长
  • 数据极小(无论怎么暴力都能过的那种)
  • 实现极其恶心

典型例题

时间复杂度

杀蚂蚁

猪国杀

做题思路

先来看一道较为简单的题目:

玩具谜题

#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);
}

按照题意直接模拟即可。

这里讲这道题的目的是为了介绍模拟题一些比较常用的处理方法:

1. 1. 离线所有询问后处理

这种方法适用于那些操作较复杂,且输入涉及一些字符串及整数的问题,虽然我们边读入边处理也是可行的,但是处理所有输入就比较麻烦,所以我们离线下来处理。

2. 2. 在读入时顺便处理,读入玩后小处理一下即输出。

这种方法适用于操作比较简单,且输入只有少量不对我们的运算有什么影响的字符串,那么边读入边处理就会使我们的代码较为简洁,省去了预处理的过程。

tips:对于一些高难度的模拟题,推荐使用方法 1 1

我们再看一道难一点的题目:

时间复杂度

这次我们不能单纯按照题意简单模拟,这时,上面提到的法一就十分的适用了。如果你用法二,在读入时处理,可行性也是有的,但是我们需要在判断错误时读入完再退出,就很麻烦。

我们先来跟着题意走,

首先有 t ( t 10 ) t(t\le10) 组数据。

int t;
cin>>t;
while(t--){
//do something
}

接下来每个程序的第一行包含一个正整数 L L 和一个字符串, L L 代表程序行数,字符串表示这个程序的复杂度,O(1)表示常数复杂度,O(n^w)表示复杂度为 O ( n w ) 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;
}

继续往下看

接下来 L L 行代表程序中循环结构中的F i x y或者 E。 程序行若以F开头,表示进入一个循环,之后有空格分离的三个字符(串)i x y, 其中 i i 是一个小写字母(保证不为 n n ),表示新建的变量名, x x y y 可能是正整数或 n n ,已知若为正整数则一定小于 100 100

对于 F F 的情况,我们先提取出里面的 i , x , y i,x,y ,将 i i 判断是否重复,再存进一个 H a s h Hash 表(这里我用 M a p Map 实现),然后用类似读优的方式提取出 x , y 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;
}

然后如果循环可以进入且后一位是 n n ,那么我们就增加我们记录的循环次数。

当然,此处要注意一个问题,那就是如果前面的循环没有进入,那么后面的循环即使很大我们也不会去处理,故此处我们用一个 l a s t n u m lastnum 来记录前面的循环是否进入。

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);

在处理 E E 的时候,我们将这个循环中记录的 i , l a s t n u m i,lastnum 以及循环次数全部更新为上一个循环的值,所以我们用一个后进先出的数据结构——栈来记录。

最后注意细节,本体就拿到满分了。

#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");
	}
}

猜你喜欢

转载自blog.csdn.net/wljoi/article/details/102578873