NOIP2017 D1T2 时间复杂度
这一道模拟题是真的特别考细心的一道题……调了半天才调出来……要是今年noip考到这样的模拟题我可能就凉凉
看到洛谷题解上有人用栈、递归,还有说离线判断的,我就在线外加各种条件就写出来了啊……正好100行
思路:
设变量ci[i]表示第i层的时间复杂度是O(n^ci[i])
对于每次进入一个循环('F'),我们考虑这么几种情况:
1、此层循环不会执行(外层循环x>y)
只需判断此层循环是否有语法错误(变量重复)即可
2、此层循环会执行,需要判断此层循环是否有语法错误(变量重复)并计算时间复杂度
读入后先判断是否有语法错误(变量重复),并记录此变量
①可以进入此层循环(x<=y)
若x为正整数,y为n,此层循环的时间复杂度=上一层时间复杂度+1;否则此层循环时间复杂度=上一层时间复杂度
②不能进入此层循环(x>y)
做标记,并记录位置(便于删除标记)
对于每次退出一个循环('E'):
1、删除变量
2、若此循环x>y(此前做的标记),则删除标记
几个实现细节:
Q:如何记录变量并判断变量是否重复?
A:用tot和alpha[]记录循环层数及其变量名称,再用利用哈希的思想用数组hash[i]表示字母i在外层循环是否出现过,哈希函数也很简单,直接用ASCII码做哈希函数,访问是直接hash['字母']即可
Q:如何判断x,y的大小?
A:不能用string重载的运算符!string重载的运算符比较方法是从前向后逐个比较……和我们的需求不一样。可以写一个dayu()函数(博主英语不好),注意x,y为n的情况,然后判断x,y的长度,最后再逐个比较。还有一些比较巧妙的实现细节读者在代码里感受一下。
代码:
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 bool hash[128];//判断字符是否使用过 7 char alpha[101];//存储使用过的字母 8 int ci[101];//每一层的时间复杂度 9 bool pd(int ans,string fuzadu)//判断时间复杂度为n^w是是否正确 10 { 11 int length=fuzadu.length(); 12 bool pd=true; 13 for(int i=length-2;i>=4;i--) 14 { 15 if(fuzadu[i]-'0'!=ans%10) 16 pd=false; 17 ans/=10; 18 } 19 return pd; 20 } 21 bool dayu(string x,string y)//上面已经判断过x为数字,y为n的情况,故此处不用判断 22 { 23 if(x=="n"&&y!="n") 24 return 1; 25 if(x.length()>y.length()) 26 return 1; 27 if(x.length()<y.length()) 28 return 0; 29 for(int i=0;i<x.length();i++) 30 { 31 if(x[i]>y[i]) 32 return 1; 33 if(x[i]<y[i]) 34 return 0; 35 } 36 return 0; 37 } 38 int main() 39 { 40 int t; 41 cin>>t; 42 while(t--) 43 { 44 memset(alpha,0,101); 45 memset(ci,0,101);//初始化ci[]数组 46 memset(hash,false,128);//初始化哈希表 47 int l,ans=0,ceng=0,place=0;//最终答案;循环层数;未进行的循环的层数标记 48 string fuzadu;//输入复杂度字符串 49 bool not_do=false,wrong=false;//此层是否执行;是否有语法错误 50 cin>>l>>fuzadu; 51 while(l--) 52 { 53 char ord;//进入循环或退出循环 54 cin>>ord; 55 if(ord=='F')//进入循环 56 { 57 char i; 58 string x,y; 59 cin>>i>>x>>y; 60 if(hash[i])//判断是否有语法错误 61 wrong=true; 62 else//若没有语法错误,存储该字符并做标记 63 { 64 alpha[++ceng]=i; 65 hash[i]=true; 66 } 67 if(!not_do)//此层循环执行,计算时间复杂度 68 { 69 if(x!="n"&&y=="n")//x为数字,y为n,复杂度+1 70 { 71 ci[ceng]=ci[ceng-1]+1; 72 ans=max(ans,ci[ceng]); 73 } 74 else if(dayu(x,y))//x>y,此层循环不执行,做标记,时间复杂度不变 75 { 76 not_do=true; 77 place=ceng; 78 } 79 else//否则时间复杂度不变 80 ci[ceng]=ci[ceng-1]; 81 } 82 } 83 else//退出循环 84 { 85 if(ceng==place)//不执行的循环已退出,重置标记 86 not_do=false; 87 hash[alpha[ceng--]]=false;//销毁变量 88 } 89 } 90 if(wrong||ceng)//有语法错误 91 cout<<"ERR"<<endl; 92 else if(ans&&pd(ans,fuzadu))//时间复杂度为O(n^ans) 93 cout<<"Yes"<<endl; 94 else if(!ans&&fuzadu[2]=='1')//时间复杂度为O(1) 95 cout<<"Yes"<<endl; 96 else 97 cout<<"No"<<endl; 98 } 99 return 0; 100 }
代码写的比较乱神犇们不喜勿喷哈
几个注意事项:
1、每组数据一定要清空各种变量&数组!
2、判断时间复杂度是否为O(n^w)要注意w不一定是一位数……我第一次就因为这个WA掉了好几个点
3、写dayu()函数的时候要严谨一些……情况比较多,最好先用大量数据测试一下(血的教训啊)