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;
}

總結

我認爲難點就是需要去記錄哪一層開始有錯誤循環和常數循環。其他還好。我太菜了。做出這題比做出機器人搬重物還高興。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章