前言
两年了。向那段拼搏的时光致敬。
分析
题目链接:时间复杂度
题目看似简单却陷阱重重,当时的我因为没有考虑到回溯的问题只拿到了40分。心痛。
题目自己去看,我先分析一下思路
如果x!=n & y=n —>答案加一。
如果(x=n & y!=n )或(x=C & y=C & x>y)–>错误的循环,他下面的循环都无效
其他情况–>答案不变,下面的循环有效
重复的变量出现后他的答案就是ERR
记录错误的循环的层数,等这一层退出后再删掉记录。在此期间任何的输入都试无效的。
如果有常数级的循环我们就从最早的那一层开始记录,有几个记录几个,到时候用层数F减去他再与ans取最大值。
我们对每一次输入的 i x y进行分析,就是上面的思路。
代码先贴上:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define N flag_one[1] //把后面的替换成前面的,省事。
using namespace std;
int n;
int T;
int F;//代表循环的深度
int ans;//所得的答案
int true_ans;//真正的答案
int code_status;//0-->yes 1-->no 2-->ERR//其实我只用到了ERR
char every_var;//输入的变量名
char sstart[50],eend[50];//x y
char tmp_str[20];
bool vis[30];//记录变量有没有出现过
char stack[200];//当前状态有多少个变量
int flag[2];//flag[0]==1-->wrong for !! 0--->true for . flag[1]==x --->F==x wrong
int flag_one[2];//记录常数级别循环 [1] --> 第几层 [2] --> 有几个
int find_true_ans()
{
int ans=0;
int len = strlen(tmp_str);
ans += tmp_str[len-2]-'0';//O()
//if(tmp_str[len-3] != '^' && tmp_str[len-3] != '(')ans += (tmp_str[len-3] - '0')*10;// ( 应该是0回头改
if(tmp_str[len-3] == '(')return 0;
if(tmp_str[len-3] != '^' && tmp_str[len-3] != '(')ans += (tmp_str[len-3] - '0')*10;// ( 应该是0回头改
return ans;
}
void init()//初始化
{
scanf("%d",&n);
memset(stack,0,sizeof(stack));
memset(vis,0,sizeof(vis));
code_status=0;
cin>>tmp_str;
true_ans = find_true_ans();
ans = 0;
flag[0] = 0;
flag[1] = 0;
flag_one[0] = 0;
flag_one[1] = 0;
F=0;
}
bool duex(char check)
{
int ans = check - 'a' + 1;
if(vis[ans])return true;
return false;
}
void del()//删除
{
int ans = stack[F] - 'a' + 1;
vis[ans] = 0;
stack[F] = 0;
F--;
if(flag[1]>F)flag[1] = 0,flag[0] = 0;
if(flag_one[0])N--;
if(flag_one[0]>F)flag_one[1] = 0,flag_one[0] = 0;
}
bool cnm()//比较常数循环是否正确。
{
int a1,b1;
int len_a = strlen(sstart);
int len_b = strlen(eend);
if(len_a == 1)a1 = sstart[0] - '0';
else a1 = (sstart[0] - '0') * 10 + (sstart[1] - '0');
if(len_b == 1)b1 = eend[0] - '0';
else b1 = (eend[0] - '0') * 10 + (eend[1] - '0');
return a1>b1;
}
int main()
{
int i;
scanf("%d", &T);
while(T--)
{
init();
for(i=1;i<=n;i++)
{
char tmp_status;
cin>>tmp_status;
if(tmp_status == 'E'){del();continue;}//wa
if(tmp_status == 'F')
{
F++;
cin>>every_var>>sstart>>eend;
//变量已经重复和出现重复的直接标记跳过
if(duex(every_var)){code_status=2;continue;}
if(code_status == 2 || flag[0])continue;
//比较一下start和end的大小,大到小就错了
if(sstart[0] != 'n' && eend[0] == 'n')
{
ans = max(ans,F-N);//wawawa
int ascii = every_var - 'a' + 1;//97-122;
stack[F] = every_var;
vis[ascii] = 1;
}
else if((sstart[0] == 'n' && eend[0] != 'n')|| cnm())//have wrong can not enter
{
flag[0] = 1;
flag[1] = F;
ans = max(ans,F-N-1);
}
else
{
if(!flag_one[0])flag_one[0] = F;
N++;
int ascii = every_var - 'a' + 1;//97-122;
stack[F] = every_var;
vis[ascii] = 1;
ans = max(ans,F-N-1);
}
}
}
if(F!=0)code_status = 2;
if(code_status == 2)printf("ERR\n");
else if(ans == true_ans)printf("Yes\n");
else printf("No\n");
}
return 0;
}
总结
我认为难点就是需要去记录哪一层开始有错误循环和常数循环。其他还好。我太菜了。做出这题比做出机器人搬重物还高兴。