P3952 时间复杂度

Posted wmq12138

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3952 时间复杂度相关的知识,希望对你有一定的参考价值。

P3952 时间复杂度

 

题目描述

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

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

F i x y
    循环体
E

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

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

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

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

输入输出格式

输入格式:

 

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

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

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

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

 

输出格式:

 

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

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

 

输入输出样例

输入样例#1: 
8
2 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
输出样例#1:
Yes
Yes
ERR
Yes
No
Yes
Yes
ERR

说明

【输入输出样例解释1】

第一个程序 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开头的语句,L10,若 xy 均 为整数,x 一定小于 y,且只有 yy 有可能为 nn。

对于 50%的数据:不存在语法错误,L <=100,且若 xy 均为整数,x 一定小于 y, 且只有 y有可能为 n

对于 70%的数据:不存在语法错误,L100。

对于 100%的数据:L100。

  思路:

  直接用getline(cin,str)一行一行读,写一个get_num获取其中的数字,将‘n‘视为一个极大的数

  • 用一个栈模拟存变量,ins标记是否被定义过,用来判ERR,used表示该变量对复杂度是否有贡献,用flag来维护最早的不能进入循环的变量(如for int i=3 ; i<=1 ; i++),因为在它之后的根本不能运行,初始化为-1,出栈时判一下如果flag=k,则其后面的语句又可以正常运行了,令flag=-1.

 

代码

技术图片
  1 #include <cstdio>
  2 #include <iostream>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <cctype>
  6 #include <cmath>
  7 #include <stack>
  8 using namespace std;
  9 
 10 #define res register int
 11 int T,n;
 12 stack <int> s;
 13 bool ins[30],used[30];//是否在栈中,对时间复杂度是否有贡献
 14 string o,code[110];
 15 
 16 template <typename T>
 17 inline T my_max(T a,T b) {return a>b?a:b;}
 18 template <typename T>
 19 inline T my_min(T a,T b) {return a<b?a:b;}
 20 
 21 inline int get_num(int &x,string c)
 22 {
 23     int tmp(0),len=c.size();
 24     while(!isdigit(c[x]) && x<len)
 25     {
 26         if(c[x]==n) {++x; return 1000000;}
 27         ++x;
 28     }
 29     while(isdigit(c[x])) {
 30         tmp=tmp*10+c[x]-0;
 31         x++;
 32     }
 33     return tmp;
 34 }
 35 
 36 inline int get_o()
 37 {
 38     int tmp(0),x=3;
 39     if(o[2]==n) tmp=get_num(x,o);
 40     else tmp=0;//O(1)对应0
 41     return tmp;
 42 }
 43 
 44 inline int check()
 45 {
 46     int now(0),cp(0);//complexity
 47     int a,b,x;
 48     while(s.size()) s.pop();
 49     memset(ins,0,sizeof(ins)); 
 50     memset(used,0,sizeof(used));
 51     int flag(-1);
 52     for(res i=1 ; i<=n ; i++)
 53     {
 54         if(code[i][0]==F)
 55         {
 56             int k=code[i][2]-a;
 57             if(ins[k]) return -1;
 58             ins[k]=true; s.push(k);
 59             x=4;
 60             a=get_num(x,code[i]); 
 61             b=get_num(x,code[i]);
 62             //flag为最早的不能循环的对应的变量k,可以正常循环时为-1
 63             if(b-a>1000 && flag==-1) 
 64             {
 65                 used[k]=true; now++;
 66                 cp=my_max(cp,now);
 67             }
 68             else if(a>b && flag==-1) 
 69                 flag=k; 
 70         }
 71         else 
 72         if(code[i][0]==E)
 73         {
 74             if(s.empty())   return -1;
 75             int k=s.top();
 76             s.pop(); ins[k]=false;
 77             if(flag==k) flag=-1;
 78             if(used[k]) now--,used[k]=false;
 79         }
 80     }
 81     if(s.size()) return -1;
 82     return cp;
 83 }
 84 
 85 int main()
 86 {
 87     scanf("%d",&T);
 88     while(T--)
 89     {
 90         scanf("%d ",&n);
 91         getline(cin,o);
 92         int x0=get_o();
 93         for(res i=1 ; i<=n ; i++)
 94             getline(cin,code[i]);
 95         int x1=check();
 96         if(x1==-1) puts("ERR");
 97         else 
 98         {
 99             if(x0==x1) puts("Yes");
100             else puts("No");
101         }
102     }
103     // system("pause");
104     return 0;
105 }
View Code

 


以上是关于P3952 时间复杂度的主要内容,如果未能解决你的问题,请参考以下文章

P3952 时间复杂度

[Luogu] P3952 时间复杂度

洛谷P3952 时间复杂度

洛谷 P3952 时间复杂度

luogu P3952 时间复杂度题解

LOJ P3952 时间复杂度 noip 暴力 模拟