Description
Solution
膜你模拟
这题很久之前刚开始学 (OI) 的时候做过一次,当时着实被虐了好几个小时才做出来,还是看了题解的。
于是怀恨在心,总之现在来复盘一下,感觉还可以,多想想,细节也不算太多。
emm没什么好说的了,直接看代码吧(有注释)。
Code
#include <bits/stdc++.h>
using namespace std;
int T, l;
char o[1000];
int stk[110], top, maxt, tim, flag, t;
//stk:记录每一层循环能否进入,且是否贡献复杂度。 1:能进入但不贡献复杂度 2:不能进入 3:能进入且贡献复杂度 top:栈顶
//maxt:记录最终出的时间复杂度。(max{tim})
//tim:可能存在并列的循环,所以记录每一时刻的时间复杂度
//flag:是否有编译错误。
//t:题目中输入的时间复杂度。
char op, x, a[10], b[10];
//输入的4个变量。
int tc[110];
//和栈同时更新,记录每一层循环的变量是多少。
bool vis[30];
//桶,用来快速判断一个变量是否被用过。
int zs(char c[]){//把 F i x y 中的 x 和 y 提取出来,判断能否进入这个循环
if(strlen(c) == 1) return c[0] - '0';
else return 10 * (c[0] - '0') + (c[1] - '0');//小于100
}
void calc(){//把输入的复杂度提取出来,就是那个O(n^w)中的 w
if(o[2] == 'n'){
if(o[5] == ')') t = o[4] - '0';
else t = 10 * (o[4] - '0') + (o[5] - '0');//w < 100
}
else t = 0;//常数的话,复杂度为0
}
int main(){
scanf("%d", &T);
while(T--){
top = flag = maxt = tim = 0;//多测清空
memset(vis, 0, sizeof(vis));
memset(tc, 0, sizeof(tc));
cin >> l >> o;
calc();//计算输入的时间复杂度
for(int i = 1; i <= l; i++){
cin >> op;
if(op == 'F'){
cin >> x >> a >> b;
if(vis[x - 'a']){//如果当前变量被用过。
flag = 1;//编译错误
top++;//还得压栈,不然后面输入就乱了。
continue;
}
if(stk[top] == 2){//上一层循环无法进入
stk[++top] = 2;//传递标记
continue;
}
tc[++top] = x - 'a';//当前变量入栈
vis[x - 'a'] = 1;//给桶打上标记
if(a[0] != 'n' && b[0] != 'n'){//两个都是数字
if(zs(a) <= zs(b)) stk[top] = 1;//1:可以进入
else stk[top] = 2;//2:无法进入
}else{//有至少一个是n
if(a[0] != 'n' && b[0] == 'n') stk[top] = 3, tim++;//3: 复杂度+1
if(a[0] == 'n' && b[0] != 'n') stk[top] = 2;
if(a[0] == 'n' && b[0] == 'n') stk[top] = 1;
}
maxt = max(maxt, tim);//更新复杂度最大值
}else{
if(!top){//栈已经空了,还在退出,直接编译错误
flag = 1;
continue;
}
if(stk[top] == 3) tim--;//判断对应循环是否贡献复杂度,如果贡献,tim--
vis[tc[top--]] = 0;//删去对应循环变量在桶中的标记
maxt = max(maxt, tim);//这个可以不写(好像)
}
}
if(flag || top || (l & 1)) puts("ERR");//编译错误(不完全)|| 桶中还有元素 || 输入长度为奇数
else if(maxt == t) puts("Yes");
else puts("No");
}
return 0;
}