NOIP2017 D1T2 时间复杂度

洛谷P3952

 

这一道模拟题是真的特别考细心的一道题……调了半天才调出来……要是今年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()函数的时候要严谨一些……情况比较多,最好先用大量数据测试一下(血的教训啊)

转载于:https://www.cnblogs.com/LiHaozhe/p/9494537.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值