NOIP2017 时间复杂度题解

前言

两年了。向那段拼搏的时光致敬。

分析

题目链接:时间复杂度
题目看似简单却陷阱重重,当时的我因为没有考虑到回溯的问题只拿到了40分。心痛。
题目自己去看,我先分析一下思路

如果x!=n & y=n —>答案加一。
如果(x=n & y!=n )或(x=C & y=C & x>y)–>错误的循环,他下面的循环都无效
其他情况–>答案不变,下面的循环有效
重复的变量出现后他的答案就是ERR
记录错误的循环的层数,等这一层退出后再删掉记录。在此期间任何的输入都试无效的。
如果有常数级的循环我们就从最早的那一层开始记录,有几个记录几个,到时候用层数F减去他再与ans取最大值。

我们对每一次输入的 i x y进行分析,就是上面的思路。
代码先贴上:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define N flag_one[1] //把后面的替换成前面的,省事。
using namespace std;
int n;
int T;
int F;//代表循环的深度
int ans;//所得的答案
int true_ans;//真正的答案
int code_status;//0-->yes 1-->no 2-->ERR//其实我只用到了ERR
char every_var;//输入的变量名
char sstart[50],eend[50];//x y
char tmp_str[20];
bool vis[30];//记录变量有没有出现过
char stack[200];//当前状态有多少个变量
int flag[2];//flag[0]==1-->wrong for !! 0--->true for .   flag[1]==x --->F==x wrong
int flag_one[2];//记录常数级别循环 [1] --> 第几层 [2] --> 有几个
int find_true_ans()
{
    int ans=0;
    int len = strlen(tmp_str);
    ans += tmp_str[len-2]-'0';//O()
    //if(tmp_str[len-3] != '^' && tmp_str[len-3] != '(')ans += (tmp_str[len-3] - '0')*10;// ( 应该是0回头改
    if(tmp_str[len-3] == '(')return 0;
    if(tmp_str[len-3] != '^' && tmp_str[len-3] != '(')ans += (tmp_str[len-3] - '0')*10;// ( 应该是0回头改
    return ans;
}
void init()//初始化
{
    scanf("%d",&n);
    memset(stack,0,sizeof(stack));
    memset(vis,0,sizeof(vis));
    code_status=0;
    cin>>tmp_str;
    true_ans = find_true_ans();
    ans = 0;
    flag[0] = 0;
    flag[1] = 0;
    flag_one[0] = 0;
    flag_one[1] = 0;
    F=0;
}
bool duex(char check)
{
    int ans = check - 'a' + 1;
    if(vis[ans])return true;
    return false;
}
void del()//删除
{
    int ans = stack[F] - 'a' + 1;
    vis[ans] = 0;
    stack[F] = 0;
    F--;
    if(flag[1]>F)flag[1] = 0,flag[0] = 0;
    if(flag_one[0])N--;
    if(flag_one[0]>F)flag_one[1] = 0,flag_one[0] = 0;
    
}
bool cnm()//比较常数循环是否正确。
{
    int a1,b1;
    int len_a = strlen(sstart);
    int len_b = strlen(eend);
    if(len_a == 1)a1 = sstart[0] - '0';
    else a1 = (sstart[0] - '0') * 10 + (sstart[1] - '0');
    if(len_b == 1)b1 = eend[0] - '0';
    else b1 = (eend[0] - '0') * 10 + (eend[1] - '0');
    return a1>b1;
}
int main()
{
    int i;
    scanf("%d", &T);
    while(T--)
    {
        init();
        for(i=1;i<=n;i++)
        {
            char tmp_status;
            cin>>tmp_status;
            if(tmp_status == 'E'){del();continue;}//wa
            if(tmp_status == 'F')
            {
                F++;
                cin>>every_var>>sstart>>eend;
                //变量已经重复和出现重复的直接标记跳过
                if(duex(every_var)){code_status=2;continue;}
                if(code_status == 2 || flag[0])continue;
                //比较一下start和end的大小,大到小就错了
                if(sstart[0] != 'n' &&  eend[0] == 'n')
                {
                    ans = max(ans,F-N);//wawawa
                    int ascii = every_var - 'a' + 1;//97-122; 
                    stack[F] = every_var;
                    vis[ascii] = 1;
                }
                else if((sstart[0] == 'n' && eend[0] != 'n')|| cnm())//have wrong can not enter
                {
                    flag[0] = 1;
                    flag[1] = F;
                    ans = max(ans,F-N-1);
                }
                else
                {
                    if(!flag_one[0])flag_one[0] = F;
                    N++;
                    int ascii = every_var - 'a' + 1;//97-122;
                    stack[F] = every_var;
                    vis[ascii] = 1;
                    ans = max(ans,F-N-1);
                }
            }
        }
        if(F!=0)code_status = 2;
        if(code_status == 2)printf("ERR\n");
        else if(ans == true_ans)printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

总结

我认为难点就是需要去记录哪一层开始有错误循环和常数循环。其他还好。我太菜了。做出这题比做出机器人搬重物还高兴。

发布了36 篇原创文章 · 获赞 29 · 访问量 3946

猜你喜欢

转载自blog.csdn.net/YUK_103/article/details/103193892
今日推荐