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