这是一道很烦人的模拟题。
特别考验代码能力,特别墨迹,特别恶心。
不是题恶心,是写起来很恶心。
先看题吧。
题目
题目描述
小明正在学习一种新的编程语言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 y和E即可计算时间复杂度。注意:循环结构允许嵌套。
接下来每个程序的第一行包含一个正整数L和一个字符串,L代表程序行数,字符串表示这个程序的复杂度,O(1)表示常数复杂度,O(n^w)表示复杂度为n^w,其中w是一个小于100的正整数(输入中不包含引号),输入保证复杂度只有O(1)和O(n^w) 两种类型。
接下来L行代表程序中循环结构中的F i x y或者E。
程序行若以F开头,表示进入一个循环,之后有空格分离的三个字符(串)i x y,其中i是一个小写字母(保证不为n),表示新建的变量名,x和y可能是正整数或n,已知若为正整数则一定小于100。
程序行若以E开头,则表示循环体结束。
输出格式:
输出文件共t行,对应输入的t个程序,每行输出Yes或No或者ERR(输出中不包含引号),若程序实际复杂度与输入给出的复杂度一致则输出Yes,不一致则输出No,若程序有语法错误(其中语法错误只有: ①F和E不匹配 ②新建的变量与已经存在但未被销毁的变量重复两种情况),则输出ERR。
注意:即使在程序不会执行的循环体中出现了语法错误也会编译错误,要输出ERR。
输入输出样例
输入样例:
82 O(1)
F i 1 1
E
2 O(n^1)
F x 1 n
E
1 O(1)
F x 1 n
4 O(n^2)
F x 5 n
F y 10 n
E
E
4 O(n^2)
F x 9 n
E
F y 2 n
E
4 O(n^1)
F x 9 n
F y n 4
E
E
4 O(1)
F y n 4
F x 9 n
E
E
4 O(n^2)
F x 1 n
F x 1 10
E
E
输出样例
YesYes
ERR
Yes
No
Yes
Yes
ERR
说明
输入输出样例解释
第一个程序i从1到1是常数复杂度。第二个程序x从1到n是n的一次方的复杂度。
第三个程序有一个F开启循环却没有E结束,语法错误。
第四个程序二重循环,n的平方的复杂度。
第五个程序两个一重循环,n的一次方的复杂度。
第六个程序第一重循环正常,但第二重循环开始即终止(因为n远大于100,100大于4)。
第七个程序第一重循环无法进入,故为常数复杂度。
第八个程序第二重循环中的变量x与第一重循环中的变量重复,出现语法错误②,输出ERR。
数据规模与约定
对于 30%的数据:不存在语法错误,数据保证小明给出的每个程序的前L/2行一定为以F开头的语句,第L/2+1行至第L行一定为以E开头的语句,L≤10,若x、y均为整数,x一定小于y,且只有y有可能为n。对于 50%的数据:不存在语法错误,L≤100,且若x、y均为整数,x一定小于y,且只有y有可能为n。
对于 70%的数据:不存在语法错误,L≤100。
对于 100%的数据:L≤100。
分析
裸模拟。
一共可以分三步。
先读入这是一定的。
先判断语法错误,如果有直接ERR走人啦。
然后计算复杂度,符合Yes,不符合No。
剩下的就是调试啦。
上代码
这道题花了一天啊啊啊啊啊。
(一如既往的独特码风)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
#include <queue>
#include <vector>
#define N 110
using namespace std;
int n;
int m;
int i=1;
int ans=0;
int flag=1;
int bz[N+N];
char s[N];
int get()
{
char c;
c=getchar();
int x;
x=0;
if(c=='n')
{
getchar();
return -1;
}
for(;c>='0'&&c<='9';c=getchar())
x=x*10+c-48;
return x;
}
void dg(int x)
{
int aans;
int hy;
hy=ans;
aans=ans;
while(i<=n)
{
i++;
char c;
c=getchar();
if(c=='E')
{
scanf("\n");
ans=aans;
return;
}
scanf(" %c ",&c);
if(bz[c]==1)
flag=0;
bz[c]=1;
int q;
int w;
q=get();
w=get();
if(q==-1&&w==-1)
dg(x+1);
if(q==-1&&w>0)
{
int jy=ans;
dg(x+1);
ans=jy;
}
if(q>0&&w==-1)
{
ans++;
dg(x+1);
}
if(q>0&&w>0)
{
int jy=-1;
if(q>w)
jy=ans;
dg(x+1);
if(jy!=-1)
ans=jy;
}
bz[c]=0;
aans=max(ans,aans);
ans=hy;
}
ans=aans;
if(i>n&&x!=0)
flag=0;
}
int main()
{
int ac;
scanf("%d\n",&ac);
for(;ac;ac--)
{
memset(bz,0,sizeof(bz));
i=1;
flag=1;
ans=0;
char c;
scanf("%d O(%c",&n,&c);
if(c=='n')
scanf("^%d",&m);
else
m=0;
scanf(")\n");
dg(0);
if(i<=n)
{
flag=0;
while(i<=n)
{
char c;
c=getchar();
if(c=='E')
scanf("\n");
else
{
scanf(" %c ",&c);
int q;
q=get();
q=get();
}
i++;
}
}
if(flag==0)
printf("ERR");
else
{
if(ans==m)
printf("Yes");
else
printf("No");
}
printf("\n");
}
return 0;
}
PS
1.格式化输入流函数“scanf”可以读入指定内容,我的代码里这点应用的很多。
2.写不明白scanf推荐使用cin,简单到爆(时间什么的就不计了吧数据太小)。
3.我用的递归,当然各种方法都可以因为递归太抽象了啊哈哈哈。