luogu P3952 时间复杂度题解

显然这是一道模拟
我们要做的就是读入一堆字符串,然后模拟这个循环。
定义某一层的复杂度为执行完这一层循环之后,消耗的复杂度。
某层循环的复杂度=\(max \{\)所有并列的下一层循环的复杂度\(\}\)。通俗点说,就是在某层循环中有分支的时候,这一层的复杂度=\(max \{\)所有分支的复杂度\(\}+\)本层复杂度。
最后复杂度=\(max \{\)所有的第一层循环复杂度\(\}\)
考虑到会有分支,所以我们采用递归来实现(当然其本质是栈,但是我不会写)。
由于要使程序不至于\(RE\),所以我们要先判断\(F\)\(E\)是否匹配。

一些细节

1.一定要记得处理完一组数据要初始化所有的东西(虽然不初始化也可以骗到73)
2.循环中会出现\(F\ i\ n\ n\)的情况,这种视作\(O(1)\)
3.在写模拟题之前,请站在出题人的角度想想怎么卡这道题,想全情况之后再写

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=214748364;
inline ll read()
{
	char ch=getchar();
	ll x=0;bool f=0;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return f?-x:x;
}
int t,ln,cnt,now,tot;
char s[101][101],fz[101],bi[101];//s[i]是程序的第i行,fz是它给出的复杂度的字符串,bi[i]表示第i个未被销毁的变量
bool usd[159],err;//usd记录未被销毁的变量,err记录是否出现ERR
int ok,fzd;
void getf()//计算它给的复杂度
{
	int len=strlen(fz+1);fzd=0;
	for(int i=1;i<=len;i++)
	{
		if(fz[i]>='0'&&fz[i]<='9')
			fzd=fzd*10+fz[i]-'0';
	}
	if(len==4) fzd=0;
}
bool xiaoyu(int k,int len)//判断第二个数是否小于第一个数
{
	int c1=0,c2=0,now1=0;
	for(int i=0;i<len;i++)//计算第一个数
	{
		if(s[k][i]>='0'&&s[k][i]<='9')
		 c1=c1*10+s[k][i]-'0';
		else if(c1>0)
		{
			now1=i;break;
		} 
	}
	if(now1!=0)
	 for(int i=now1;i<len;i++)//计算第二个数
     {
     	if(s[k][i]>='0'&&s[k][i]<='9')
     	 c2=c2*10+s[k][i]-'0';
	 }	
	if(!c2&&(s[k][4]>'9')&&c1) return 1;//处理"n 数字","n n"的情况
	if(c1>c2&&c2!=0) return 1;
	return 0; 
} 
int work()//计算一个"第一层循环"的复杂度
{
	int rtn=0;if(err) return 0;
	char x=s[now][2];bi[++tot]=x;
	if(usd[x]) {err=1;printf("ERR\n");return 0;}//判断是否出现重复变量
	usd[x]=1;
	int rst=0,lenn=strlen(s[now]);
	if(s[now][lenn-1]=='n'&&s[now][4]!='n') rst=1;//处理O(n)+特判"n n"的情况
	if(xiaoyu(now,lenn)) rst=-inf;//如果不能进入循环,则消除这次答案的影响(进入之后的循环判断ERR)
	now++;
	while(s[now][0]!='E')
	{
		if(err) return 0;
		rtn=max(rtn,work());
		now++;//手动进入程序的下一行(虽然不写也有55pts)
		if(err) return 0;
	}
	if(s[now][0]=='E')
		usd[bi[tot--]]=0;
	rtn+=rst;	
	rtn=max(rtn,0);
	return rtn;
}
int main()
{
	t=read();
	while(t--)
	{
		ln=read();scanf("%s",fz+1);cnt=0;now=1;memset(usd,0,sizeof(usd));err=0;//一堆初始化
		gets(s[0]);
		for(int i=1;i<=ln;i++)//把字符串全部读入之后手动模拟程序的每一行
		{
			gets(s[i]);
			if(s[i][0]=='F') cnt++;
			if(s[i][0]=='E') cnt--;
		}
		if(cnt)//如果不匹配
		{printf("ERR\n");continue;}
		ok=work();
		while(now<ln)//可能存在多个"第一层循环"
		{now++;ok=max(ok,work());}
		getf();//计算它给出的复杂度
		if(err) continue;
		if(ok!=fzd) printf("No\n");
		if(ok==fzd) printf("Yes\n"); 
	}
}
posted @ 2020-01-11 21:16  千载煜  阅读(119)  评论(0编辑  收藏  举报