洛谷 P3952时间复杂度 (本地AC测评RE的伪题解)

时间:2023-03-09 16:16:01
洛谷 P3952时间复杂度 (本地AC测评RE的伪题解)

【题目描述】

小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序, 于是你的机会来啦!下面请你编写程序来判断小明对他的每个程序给出的时间复杂度是否正确。

A++语言的循环结构如下:

F i x y
循环体
E

其中F i x y表示新建变量 i(变量 i 不可与未被销毁的变量重名)并初始化为 x, 然后判断 i 和 y 的大小关系,若 i 小于等于 y 则进入循环,否则不进入。每次循环结束后 i 都会被修改成 i+1,一旦 i 大于 y终止循环。

x 和 y 可以是正整数(x 和 y 的大小关系不定)或变量 n。n 是一个表示数据规模的变量,在时间复杂度计算中需保留该变量而不能将其视为常数,该数远大于 100。

“E”表示循环体结束。循环体结束时,这个循环体新建的变量也被销毁。

注:本题中为了书写方便,在描述复杂度时,使用大写英文字母“O”表示通常意义下“Θ”的概念。

【输入格式】

输入文件第一行一个正整数 t,表示有 t(t≤10)个程序需要计算时间复杂度。 每个程序我们只需抽取其中 F i x yE即可计算时间复杂度。注意:循环结构 允许嵌套。

接下来每个程序的第一行包含一个正整数 L 和一个字符串,L 代表程序行数,字符 串表示这个程序的复杂度,O(1)表示常数复杂度,O(n^w)表示复杂度为n^w,其 中w是一个小于100的正整数(输入中不包含引号),输入保证复杂度只有O(1)O(n^w) 两种类型。

接下来 LL 行代表程序中循环结构中的F i x y或者 E。 程序行若以F开头,表示进入一个循环,之后有空格分离的三个字符(串)i x y, 其中 ii 是一个小写字母(保证不为n),表示新建的变量名,x 和 y 可能是正整数或 n ,已知若为正整数则一定小于 100。

程序行若以E开头,则表示循环体结束。

【输出格式】

输出文件共 t 行,对应输入的 t 个程序,每行输出YesNo或者ERR(输出中不包含引号),若程序实际复杂度与输入给出的复杂度一致则输出Yes,不一致则输出No,若程序有语法错误(其中语法错误只有: ① F 和 E 不匹配 ②新建的变量与已经存在但未被销毁的变量重复两种情况),则输出ERR 。

注意:即使在程序不会执行的循环体中出现了语法错误也会编译错误,要输出 ERR

【输入输出样例】

输入

 O()
F i
E
O(n^)
F x n
E
O()
F x n
O(n^)
F x n
F y n
E
E
O(n^)
F x n
E
F y n
E
O(n^)
F x n
F y n
E
E
O()
F y n
F x n
E
E
O(n^)
F x n
F x
E
E

输出

Yes
Yes
ERR
Yes
No
Yes
Yes
ERR

这题花了我近三个小时,本地AC评测就会RE两个点,心累……

这题当然是模拟,但是要考虑的东西很多,所以这题是一道蓝题。

1.首先考虑一下为什么会ERR:

1)有F而没有E

2)有E而没有F

3)变量用过了

看见前两个条件就非常自如的联想到了栈。

bool ok=true;
int word[]; if(word[i-'a'+]!=) word[i-'a'+]=;
else ok=false; if(p<) ok=false;//p是指针 if(ok==false) {printf("ERR\n");continue;}

2.再考虑一下计算复杂度

1)前为n且后为n -> 复杂度常数级别

2)前为n且后不为n -> 复杂度常数级别

3)前不为n且后为n -> 复杂度n级别

4)前不为n且后不为n -> 复杂度常数级别

5)如果在这条循环之前有一条循环不执行(前不为n且后为n或者说两个常数前面的比后面的大)-> 复杂度常数级别

for(int j=;j<len;j++)
{
if(s[j]>e[j]&&s[j]>=''&&s[j]<=''&&e[j]>=''&&e[j]<='')
{wyq=true;break;}
if(s[j]<e[j]&&s[j]>=''&&s[j]<=''&&e[j]>=''&&e[j]<='') break;
}//若都是常数,进行比较
if(strlen(s)>strlen(e)&&s[]>=''&&s[]<=''&&e[]>=''&&e[]<='') h[p+].lxp=true;
if(wyq||(s[]=='n'&&e[]!='n')) h[p+].lxp=true;//判断代码是否有运行

for(int k=;k<=p+;k++)
if(h[k].lxp==true)
{h[++p].data='';h[p].old=i;wyc=true;break;}//前面的比后面的大,当作是常数级别
if(wyc) continue;
if(s[]=='n'&&e[]=='n') {h[++p].data='';h[p].old=i;}
if(s[]=='n'&&e[]!='n') {h[++p].data='';h[p].old=i;}
if(s[]!='n'&&e[]=='n') {h[++p].data='n';h[p].old=i;}
if(s[]!='n'&&e[]!='n') {h[++p].data='';h[p].old=i;}

3.再然后就是最后的判断和最开始的初始化

感觉没什么问题可还是RE了

上代码

#include<bits/stdc++.h>
using namespace std;
int t,p=;
struct node{
char data;
char old;
int maxn;//用来储存栈中第i层最大的时间复杂度
bool lxp;//判断代码是否有运行
}h[];//栈,看是否匹配
int l,word[];//word是看这个变量用过没有
char o[];
int num=,sum=;
int main()
{
// freopen("hh1.in","r",stdin);
// freopen("hh1.out","w",stdout);
scanf("%d",&t);
while(t--)
{
for(int k=;k<=;k++) {h[k].maxn=;h[k].data=;h[k].old=;h[k].lxp=false;}
for(int i=;i<=;i++) word[i]=;
sum=;p=;num=;//每条程序重置一次
scanf("%d%s",&l,o);
bool flag=false;//判断是常数还是n^w
bool ok=true;
if(strlen(o)==) flag=true;
else
{
int n=strlen(o);
for(int i=;i<n;i++)
if(o[i]<=''&&o[i]>='')
num=num*+o[i]-'';
}
while(l--)
{
char c,i,s[],e[];
cin>>c;
if(c=='F')
{
sum=;//将指数重置
cin>>i>>s>>e;
bool wyq=false,wyc=false;//临时变量,不用管意义
int len=strlen(s);
for(int j=;j<len;j++)
{
if(s[j]>e[j]&&s[j]>=''&&s[j]<=''&&e[j]>=''&&e[j]<='')
{wyq=true;break;}
if(s[j]<e[j]&&s[j]>=''&&s[j]<=''&&e[j]>=''&&e[j]<='') break;
}//若都是常数,进行比较
if(strlen(s)>strlen(e)&&s[]>=''&&s[]<=''&&e[]>=''&&e[]<='') h[p+].lxp=true;
if(wyq||(s[]=='n'&&e[]!='n')) h[p+].lxp=true;//判断代码是否有运行
if(word[i-'a'+]!=) word[i-'a'+]=;
else ok=false;
for(int k=;k<=p+;k++)
if(h[k].lxp==true)
{h[++p].data='';h[p].old=i;wyc=true;break;}//前面的比后面的大,当作是常数级别
if(wyc) continue;
if(s[]=='n'&&e[]=='n') {h[++p].data='';h[p].old=i;}
if(s[]=='n'&&e[]!='n') {h[++p].data='';h[p].old=i;}
if(s[]!='n'&&e[]=='n') {h[++p].data='n';h[p].old=i;}
if(s[]!='n'&&e[]!='n') {h[++p].data='';h[p].old=i;}
}
if(c=='E')
{
if(h[p].data==) p--;
if(h[p].data=='n') sum=h[p+].maxn+;//前一层为n^1级别的就指数+1
else sum=h[p+].maxn*;
h[p].maxn=max(sum,h[p].maxn);//存储到这时最大的指数
h[p+].maxn=;
word[h[p].old-'a'+]=;
h[p].lxp=false;
p--;
if(p<) ok=false;
}
}
if(ok==false) {printf("ERR\n");continue;}//如果变量用过了或括号不匹配,错误,跳出去
if(p>) {printf("ERR\n");continue;}
if(flag&&h[].maxn==) printf("Yes\n");
else if(!flag&&h[].maxn-==num) printf("Yes\n");
else printf("No\n");
}
return ;
}