P3952 [NOIP2017 提高组] 时间复杂度
# [NOIP2017 提高组] 时间复杂度
## 题目背景
NOIP2017 提高组 D1T2
## 题目描述
小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序, 于是你的机会来啦!下面请你编写程序来判断小明对他的每个程序给出的时间复杂度是否正确。
A++语言的循环结构如下:
```cpp
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` 表示循环体结束。循环体结束时,这个循环体新建的变量也被销毁。
注:本题中为了书写方便,在描述复杂度时,使用大写英文字母 $\operatorname O$ 表示通常意义下 $Θ$ 的概念。
## 输入格式
输入文件第一行一个正整数 $t$,表示有 $t$($t \le 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`。
## 样例 #1
### 样例输入 #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` 开头的语句,$L \le 10$,若 $x$、$y$ 均为整数,$x$ 一定小于 $y$,且只有 $y$ 有可能为 $n$。
对于 $50\%$ 的数据:不存在语法错误,$L \le 100$,且若 $x$、$y$ 均为整数,$x$ 一定小于 $y$, 且只有 $y$ 有可能为 $n$。
对于 $70\%$ 的数据:不存在语法错误,$L \le 100$。
对于 $100\%$ 的数据:$L \le 100$。
---
如果需要Hack请私信@zhouyonglong或发讨论,提供数据和能Hack掉的本题的AC记录。
核心思想:三个板块 hash容器*1 变量*n
很明显的是这题字符串处理比较麻烦,额,对我来说比较麻烦,字符串处理太细节了
三个板块: 时间复杂度处理板块,入栈出栈板块,销毁板块 ;
hash容器: unordered_map
一大堆变量。
#include<bits/stdc++.h> using namespace std; string n="n"; int main() { int t; cin >> t; while(t--) { int cnt=0; int cou; //操作次数 string O; //待处理的O(n^?)部分的字符串 string stand; //时间复杂度的标准 string ans; //标记答案,主要是为了标记为ERR int ceng=0; //当前时间复杂度 int max_ceng=0; //最大的时间复杂度 int stop=0; // 合法(指的是语法正确)但是进入非法 //进入非法的意思为,例如n,4这种i=n,i<=4这种循环式合法输入,但是不合法进入循环 //如果产生这种不合法,进行标记非法. cin >> cou >> O; stack<pair<char,string> > ch;//栈第一个记录的是 进栈模式, //1.我们对合法输入但非法进入的标记 为 S ; //2.我们对合法进入并且对时间复杂度有贡献的设为 T; //3.我们对合法进入但对时间复杂度无贡献的设为 F; //第二个则是变量的索引,如果我们要退出栈(循环),就需要销毁相应的变量; //通过索引我们可以找到相应的变量. unordered_map <string,int> m;//储存变量名 for(int i=0;i<O.size();i++)//提取给出的标准的时间复杂度 { if(O[i]=='n'){ while(O[i+2]!=')')//这块注意一下,反正我第一次处理就出错了 { stand+=O[i+2]; i++; } break; } if(O[i]=='1'){stand="0";break;} } while(cou--) { char op; cin >> op; if(op=='F') { string var,st,ed; cin >> var >> st >> ed; //var 变量 ; st开始 ; ed结束条件; if(m.find(var)==m.end())m.insert(pair<string,int>(var,1));//如果没有定义过变量则添加一个进去 else {ans="ERR";}//如果已经有变量添加过了,那此时是不合法的,但是由于还有别的字符串进来,所以不能直接break if(st!=n&&(1<=stoi(st))&&ed==n&&cnt==0) // 这里字符串处理注意一下,另外如果已经进入stop非法进入的情况下,除非非法进入的所有循环结束,否则进来的循环都对时间复杂度没有贡献 {ceng++; max_ceng=max(max_ceng,ceng); op='T';} int stop=0;//标记是否为非法进入 if((st==n&&ed!=n)||(ed!=n&&st!=n&&stoi(st)>stoi(ed)))//字符串处理注意一下 { stop=1; //已标记 cnt++; //很显然,非法进入是可以重复的,只有这些非法进入都出去,才能计算时间复杂度,所有用cnt来记录目前栈(循环)中有多少个非法进入 ch.push({'S',var}); } if(!stop)ch.push({op,var}); } else { if(ch.empty()){ans="ERR";}//当退出循环发现无循环可退,那就是非法输入了 else { auto temp=ch.top(); if(temp.first=='T')ceng--;//发现是合法循环层退出,那当前循环层--; if(temp.first=='S')cnt--;//出栈非法进入,那也要cnt--,让非法进入--; m.erase(temp.second);//销毁变量 ch.pop();//出栈 } } } if(!ch.empty())ans="ERR";//结算是发现还有循环没退出来,那就是不合法 if(ans=="ERR")puts("ERR"); else { if(to_string(max_ceng)==stand)puts("Yes");//字符串比较. else puts("No"); } } return 0; }
写了非常多的注释,我觉得对你很有必要,基本每一步我都解释了,加油,少年
由于这题我一直在WA,我可以给一些参考性建议对你的分数
27分 ---- 你可能没有销毁变量
说白了,你可能 op==E 的 时候没有销毁变量 具体可以参考我的OP==E时候的代码
55分 ---- 你是否未退出循环?
出栈的时候不会没有ceng--吧,或者ceng处理有问题 建议cout<<"ceng= "<<ceng<<endl;来debug
第四个测试点测试数据:
3 36 O(n^7) F a 88 98 F b 29 n E E F a 86 90 E F a 14 15 F b 27 n F c 69 n F d 40 64 F e 61 87 F f 6 n F g 13 n F h 72 n F i 23 n E E E E E E E E E F a 66 n F b 29 91 F c 51 n F d 37 n F e 29 77 F f 28 69 E E E E E E 44 O(n^9) F a 84 85 F b 59 82 F c 81 n F d 28 n F e 63 95 F f 64 n F g 24 70 F h 47 n F i 3 78 F j 56 n F k 36 n F l 49 n F m 49 n F o 89 92 F p 34 n E E E E E E E E E E E E E E E F a 90 n F b 1 n F c 9 n F d 53 86 F e 75 n F f 8 n F g 42 n E E E E E E E 30 O(n^7) F a 63 n F b 53 69 F c 71 n F d 62 86 F e 4 n F f 44 n F g 32 83 F h 58 92 F i 29 n E E E E E E E E E F a 77 96 F b 89 n F c 24 n E E E F a 64 90 F b 45 65 F c 17 n E E E
输出:
No
Yes
No
64分 ---- 你字符串处理是不是有问题?
去看看自己O[i]处理的对不对?或者看看自己的stoi用的对不对?或者自己写的字符串处理对不对
第五个测试点数据:
3 48 O(n^10) F a 87 n F b 39 n F c 26 n F d 5 n E E F e 35 n F f 81 n F g 32 n F h 45 55 F i 16 n F j 24 n F k 27 n F l 20 n F m 59 n E E E E E E E E E E E F a 82 n F b 85 n F c 75 n F d 54 n F e 3 n F f 77 92 F g 54 n F h 29 n F i 3 92 F j 34 94 F k 23 n E E E E E E E E E E E 52 O(n^10) F a 53 69 F b 85 n F c 77 n F d 25 88 F e 8 n F f 57 67 F g 8 91 F h 11 41 F i 24 40 E E E E E E E E E F a 2 72 F b 87 n F c 27 n F d 1 n F e 36 n F f 39 62 F g 42 n F h 23 n F i 22 n F j 55 n F k 74 n F l 73 n F m 20 23 E E E E E E E E E E E E E F a 68 n F b 72 n F c 16 n F d 88 n E E E E 62 O(n^11) F a 53 86 F b 33 n F c 46 98 F d 20 n F e 11 n F f 60 76 F g 76 n F h 45 59 F i 87 n F j 53 n F k 36 n F l 34 96 F m 2 n F o 87 n F p 52 n E E E E E E E E E E E E E E E F a 35 64 F b 18 38 F c 69 99 F d 69 88 F e 75 99 F f 79 n F g 19 n F h 82 94 F i 58 n E E E E E E E E E F a 38 n F b 14 n F c 38 n F d 12 n F e 81 92 F f 16 n F g 25 n E E E E E E E
输出:
Yes
Yes
No
91分 ---- 或许你还是字符串有问题。。也有可能你对题干有错误的理解
首先,注意字符串的比较 这里容易出问题 我们需要比较的st,ed的整数形式而非字符串形式,所以严谨一点 ,加点括号和特盘
以下情况的考虑你是否考虑错了
一: n n的情况下是O(1)
二: 3 1 的情况下也是非法进入
9 22 O(n^7) F a 70 94 F b 90 94 E E F a 29 n F b 22 n F c 4 27 F d 85 n F e 24 n F f 56 87 F g 19 66 F h 6 41 F i 78 92 F j 7 n E E E E E E E E 66 O(n^8) F a 87 n F b 70 n F c 65 n F d 85 n F e 35 n E E E E E F a 33 59 F b 74 n F c 3 n F d 81 88 F e 82 97 F f 87 98 F g 49 88 F h 72 98 F i 56 n F j 48 76 F k 90 n F l 54 n F m 86 n E E E E E E E E E E E E E F a 32 46 F b 56 n F c 5 n F d 65 75 F e 4 n F f 78 n F g 75 n F h 82 n F i 52 n F j 53 n E E E E E E E E E E E E F a 3 n F b 6 n F c 22 n F d 42 n E E E E 60 O(n^11) F a 46 n F b 3 64 F c 8 n F d 19 n F e 30 n F f 22 16 F g 40 n F h 10 n F i 25 n F a 62 n E E E E E E E E E E F a 81 n F b 37 n F c 44 n F d 13 n F e 56 94 E E E E E F a 50 n F b 75 n F c 3 74 F d 58 n F e 15 n F f 43 n F g 32 n F h 25 35 F i 47 n F j 56 n F k 53 81 F l 63 n F m 78 87 F o 73 n F p 90 n E E E E E E E E E E E E E E E 36 O(n^7) F a 68 n F b 42 n F c 16 n F d 26 89 E E E E F a 7 44 F b 13 60 F c 85 97 F d 38 74 F e 73 n F f 65 83 F g 52 n F h 3 5 F i 88 n F j 24 n F k 81 n F l 1 n F m 85 n E E E E E E E E E E E E E F a 36 67 E 84 O(n^11) F a 85 86 F b 76 90 F c 45 75 F d 41 43 F e 87 96 F f 18 n F g 15 76 F h 47 n E E E E E E E E F a 61 n F b 62 n F c 3 32 F d 4 n F e 18 n F f 53 74 F g 64 n F h 87 n F i 77 n F j 60 69 F k 67 96 F l 34 n F m 62 n E E E E E E E E E E E E E F a 74 n F b 17 n F c 9 n F d 43 n F e 82 n F f 57 65 F g 35 n F h 29 n F i 37 95 E E E E E E E E E F a 31 n F b 14 71 F c 74 n F d 81 n F e 8 n F f 11 n F g 29 n F h 19 n F i 60 n F j 68 79 F k 63 n F l 11 n E E E E E E E E E E E E 62 O(n^10) F a 26 n F b 84 n F c 69 73 F d 59 n F e 13 n E E E E E F a 46 n F b 61 n F c 47 n F d 43 n F e 77 n F f 33 n F g 32 n F h 71 n F i n n F j 35 n F k 47 86 F l 53 n E E E E E E E E E E E E F a 31 38 F b 74 95 F c 6 66 F d 68 84 F e 72 n F f 1 n F g 47 89 F h 89 n F i 5 n F j 34 n F k 2 n F l 27 n E E E E E E E E E E E E F a 33 58 F b 5 70 E E 34 O(n^4) F a 50 n F b 6 78 F c 9 10 F d 6 n F e 17 n F f 24 n E E E E E E F a 50 56 F b 2 17 F c 57 n F d 46 86 F e 38 60 F f 56 n F g 77 94 F h 26 71 F i 59 n F j 22 40 F k 13 n E E E E E E E E E E E 56 O(n^5) F a 9 n F b 64 n F c 17 n F d n 6 F e 59 n F f 36 n F g 48 64 F h 17 n E E E E E E E E F a 20 n F b 19 n F c 18 55 F d 46 n F e 58 70 F f 12 46 E E E E E E F a 20 n F b 35 n F c 44 67 F d 40 49 F e 71 75 F f 61 n F g 76 n F h 3 n F i 99 60 F j 59 80 F k 27 n F l 30 n F m 5 n F o 86 n E E E E E E E E E E E E E E 2 O(n^1) F a n n E
输出:
ERR
ERR
ERR
Yes
No
Yes
Yes
Yes
No
最后祝各位早点de到这题的bug,另外,有什么补充请说出来,这对我很重要.谢谢!
浙公网安备 33010602011771号