noip2017d1t2

本代码是在洛谷看过YWY_wys dalao的讲解后学着打出来的,主要是便于自己理解记忆。

  • 本蒟蒻对字符、字符串的处理实在太渣了。这个博客这个博客对string和char都介绍的不错。
  • 一定要数好字符所在的位置顺序,否则……
  • 每输入一组数据,先读入给出的时间复杂度,再读入并储存l个字符串,然后进行判断和处理。
  • sread函数:提取字符串中的数据,一次仅读一个数(不是数字)或n,写法类似于快读。
  • geto函数:提取给出的的时间复杂度。
  • check函数:结果用res保存,若返回值为-1,则代表有语法错误,否则代表代复杂度。当前复杂度用now保存。需要一个栈(stack)以便最后判断语法错误。每有一个有效循环即将其变量名入栈并将ins[k]标记为1,若已被标记则表明该变量名已被用过。
  • 遍历一遍代码:

如果遇到了F,首先获取变量名,用k保存,获取 F x i j 中的 i j,分别用 a b 保存。将 k 进栈。

如果 b<a ,那么没有进入循环。用一个 flag 来保存最早的没有进入循环的 k。如果都进入了,则flag始终为-1。

如果 a<=b ,代表进入循环,此时若 b-a>1000 并且 flag 为 -1 ,则本层循环对复杂度有贡献,执行 now++ 操作。同时我们用 ef[26] 保存 now++ 时 k 的信息,即ef[k]=true,并更新res。

如果遇到了E,那么同样获取变量名 k ,将k弹出栈。同时判断 flag是否等于 k ,若为 k ,代表已经出了没有贡献的循环,然后使flag=-1。再判断k是否对复杂度有贡献,若有,则当前复杂度减小,即now–,ef[k]=false;

最后return res;

再在此基础上考虑有语法错误的情况:

F 和 E 不匹配 (类似于括号匹配):
① F比E少,在函数运行到‘E’时判断栈是否为空,若为空则有语法错误,直接return -1。

② F比E多,在遍历完代码后判断栈是否不为空,若不空则有语法错误,直接return -1。

新建的变量与已经存在但未被销毁的变量重复:
用一个bool数组 ins[26] 表示当前,哪些变量被用过。那么只需在原来的基础上: 在k入栈时,判断k是否已经被用过(即k是否在栈中),若用过则有语法错误,直接return -1。

代码:

#include<bits/stdc++.h>
using namespace std;

int t,w,v,l;
string o,code[105];//code[105]是一行一行存字符串的,若要取出某个字符用code[x]
[y]
int sread(int &x,string c)//开始没搞懂&x什么意思,同桌dalao说是指针然并不能听懂。不过想起老师讲过:&取地址符可以在子函数内直接修改调用它的函数中x的值
{
	int res=0;
	int len=c.size();
	while(c[x]<'0'||c[x]>'9'&&x<c.size())
	{
		if(c[x]=='n')
		{
			x++;
			return 1000000;
		}
		x++;
	}
	while(c[x]>='0'&&c[x]<='9')
	{
		res=res*10+c[x]-'0';
		x++;
	}
	return res;
}

int geto()
{
	int res=0,x=3;
	int len=o.size();
	if(o[2]=='n') res=sread(x,o);
	else res=0;
	return res;
}

int check()
{
	int res=0,now=0;
	int a,b,x;
	stack<int>s;
	int flag=-1;
	bool ins[26];
	bool ef[26];
	memset(ins,0,sizeof(ins));
	memset(ef,0,sizeof(ef));	
	for(int i=1;i<=l;i++)
	{
		if(code[i][0]=='F')
		{
			int k=code[i][2]-'a';
			if(ins[k]) return -1;
			s.push(k); ins[k]=1;
			x=4;
			a=sread(x,code[i]);
			b=sread(x,code[i]);//a与b虽然代码相同,但因为x值的改变使得两者不同,可判别先后顺序并比较二者大小从而辨别语法错误
			if(b-a>1000)
			{
				if(flag==-1)
				{
					now++;
					res=max(res,now);
					ef[k]=1;
				}
			}
			if(a>b)
			{
				if(flag==-1) flag=k;
			}
		}
		if(code[i][0]=='E')
		{
			if(s.empty()) return -1;
			int k=s.top();
			s.pop();ins[k]=0;
			if(flag==k) flag=-1;
			if(ef[k])
			{
				ef[k]=0;
				now--;
			}
		}
	}
	if(s.size()) return -1;
	return res;
}

int main()
{
//	freopen("in.txt","r",stdin);
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d ",&l);getline(cin,o);
		w=geto();
		for(int i=1;i<=l;i++) getline(cin,code[i]);
		v=check();
		if(v==-1) printf("ERR\n");
		else
		{
			if(w==v) printf("Yes\n");
			else printf("No\n");
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值