Luogu 3952(NOIP2017 D1T2 时间复杂度)(模拟+栈)

传送门

题意:

给你T组简化代码,每组L行,给一个复杂度。模拟循环,计算复杂度,判断语法是否有误以及给定复杂度是否正确。

 

题解:

略(用栈模拟整个过程),方法基本就这一个,具体实现方法千变万化(代码中有注释)

 

本题大概有两大难点:

①同一层中可能有若干个平行的循环(如样例第五个程序),实际复杂度应取其中最大复杂度

②对于没有进入的循环不能直接跳过不处理(因为后面出现的语法错误也算数),后面退到当前循环中要特判(这也是要开第三个栈sa的原因)

 

注意:

①建议把题目中关键信息复制到代码头或一个单独文本中,边写边比对

②读入的复杂度和变量值可能不是一位数

③语法错误1可能不仅是F多了,也可能使E多了

④读入可用getline,也可用变形的读入优化(具体见代码)

 

至此NOIP2017全部AC,虽然现在不一定都能做但至少都自己AC过一遍,这一刻来得虽然稍微晚了一丢丢,但还是很有纪念意义。任重而道远,同志仍须努力!祝NOIP 2018 rp++!

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
const int INF=0x3f3f3f3f; 
inline int read() {
	int x=0;char c=getchar();
	while (c<'0'||c>'9') {if (c=='n') return INF;c=getchar();}
	while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	return x;
}
bool ve[26];//变量名是否存在
int step;//当前循环层数
int hisans;//给定复杂度
bool gram;//语法错误
int numline;//程序行数
stack<char > sv;//当前层变量名
stack<int > sc;//当前层复杂度
stack<int > sa;//当前是否有效进入循环
int c[52];//各层实际复杂度
inline void smax(int &x,int y) {
	x=max(x,y);
}
void clean() {
	memset(ve,false,sizeof(ve));
	memset(c,0,sizeof(c));
	gram=false;
	step=0;
	numline=read();
	while (!sv.empty()) sv.pop();
	while (!sc.empty()) sc.pop();
	while (!sa.empty()) sa.pop();
}
int main() {
//	freopen("P3952_.in","r",stdin);
	int kase=read();
	while (kase--) {
		clean();
		char his[10];
		scanf("%s",his);
		if (his[2]=='1') hisans=0;
		else {
			if (his[5]==')') hisans=his[4]-'0';
			else if (his[6]==')') hisans=(his[4]-'0')*10+his[5]-'0';
			else if (his[7]==')') hisans=(his[4]-'0')*100+(his[5]-'0')*10+his[6]-'0';
		}
 		for (int line=1;line<=numline;++line) {
			char fe;//'F' or 'E'?
			while (!isalpha(fe=getchar()));
			if (fe=='F') {//进循环体
				char ch;//当前变量名 
				while (!isalpha(ch=getchar()));
				if (ve[ch-'a']) gram=true;
				ve[ch-'a']=true;
				int x=read(),y=read();
				if (gram) continue;//语法错误则直接跳过
				++step;
				if (x>y) {
					sv.push(ch);
					sc.push(0);
					sa.push(false);
				} else if (x==y) {
					sv.push(ch);
					sc.push(0);
					sa.push(true);
				} else if (x<y) {
					if (y==INF) {
						sv.push(ch);
						sc.push(1);
						sa.push(true);
					} else {
						sv.push(ch);
						sc.push(0);
						sa.push(true);
					}
				}
			} else {//出循环体
				if (sv.empty()) gram=true;
				if (gram) continue;//语法错误则直接跳过
				char nv=sv.top();sv.pop();
				ve[nv-'a']=false;
				int nc=sc.top();sc.pop();
				bool na=sa.top();sa.pop();
				int nxtc=c[step];
				c[step--]=0;
				if (na) smax(c[step],nc+nxtc);
			}
		}
		if (!sc.empty()) gram=true;
		if (gram) puts("ERR");
		else if (c[0]^hisans) puts("No");
		else if (c[0]==hisans) puts("Yes");
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值