luogu P3952 时间复杂度题解

Posted lcez56jsy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P3952 时间复杂度题解相关的知识,希望对你有一定的参考价值。

显然这是一道模拟
我们要做的就是读入一堆字符串,然后模拟这个循环。
定义某一层的复杂度为执行完这一层循环之后,消耗的复杂度。
某层循环的复杂度=(max {)所有并列的下一层循环的复杂度(})。通俗点说,就是在某层循环中有分支的时候,这一层的复杂度=(max {)所有分支的复杂度(}+)本层复杂度。
最后复杂度=(max {)所有的第一层循环复杂度(})
考虑到会有分支,所以我们采用递归来实现(当然其本质是栈,但是我不会写)。
由于要使程序不至于(RE),所以我们要先判断(F)(E)是否匹配。

一些细节

1.一定要记得处理完一组数据要初始化所有的东西(虽然不初始化也可以骗到73)
2.循环中会出现(F i n n)的情况,这种视作(O(1))
3.在写模拟题之前,请站在出题人的角度想想怎么卡这道题,想全情况之后再写

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=214748364;
inline ll read()
{
    char ch=getchar();
    ll x=0;bool f=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return f?-x:x;
}
int t,ln,cnt,now,tot;
char s[101][101],fz[101],bi[101];//s[i]是程序的第i行,fz是它给出的复杂度的字符串,bi[i]表示第i个未被销毁的变量
bool usd[159],err;//usd记录未被销毁的变量,err记录是否出现ERR
int ok,fzd;
void getf()//计算它给的复杂度
{
    int len=strlen(fz+1);fzd=0;
    for(int i=1;i<=len;i++)
    {
        if(fz[i]>='0'&&fz[i]<='9')
            fzd=fzd*10+fz[i]-'0';
    }
    if(len==4) fzd=0;
}
bool xiaoyu(int k,int len)//判断第二个数是否小于第一个数
{
    int c1=0,c2=0,now1=0;
    for(int i=0;i<len;i++)//计算第一个数
    {
        if(s[k][i]>='0'&&s[k][i]<='9')
         c1=c1*10+s[k][i]-'0';
        else if(c1>0)
        {
            now1=i;break;
        } 
    }
    if(now1!=0)
     for(int i=now1;i<len;i++)//计算第二个数
     {
        if(s[k][i]>='0'&&s[k][i]<='9')
         c2=c2*10+s[k][i]-'0';
     }  
    if(!c2&&(s[k][4]>'9')&&c1) return 1;//处理"n 数字","n n"的情况
    if(c1>c2&&c2!=0) return 1;
    return 0; 
} 
int work()//计算一个"第一层循环"的复杂度
{
    int rtn=0;if(err) return 0;
    char x=s[now][2];bi[++tot]=x;
    if(usd[x]) {err=1;printf("ERR
");return 0;}//判断是否出现重复变量
    usd[x]=1;
    int rst=0,lenn=strlen(s[now]);
    if(s[now][lenn-1]=='n'&&s[now][4]!='n') rst=1;//处理O(n)+特判"n n"的情况
    if(xiaoyu(now,lenn)) rst=-inf;//如果不能进入循环,则消除这次答案的影响(进入之后的循环判断ERR)
    now++;
    while(s[now][0]!='E')
    {
        if(err) return 0;
        rtn=max(rtn,work());
        now++;//手动进入程序的下一行(虽然不写也有55pts)
        if(err) return 0;
    }
    if(s[now][0]=='E')
        usd[bi[tot--]]=0;
    rtn+=rst;   
    rtn=max(rtn,0);
    return rtn;
}
int main()
{
    t=read();
    while(t--)
    {
        ln=read();scanf("%s",fz+1);cnt=0;now=1;memset(usd,0,sizeof(usd));err=0;//一堆初始化
        gets(s[0]);
        for(int i=1;i<=ln;i++)//把字符串全部读入之后手动模拟程序的每一行
        {
            gets(s[i]);
            if(s[i][0]=='F') cnt++;
            if(s[i][0]=='E') cnt--;
        }
        if(cnt)//如果不匹配
        {printf("ERR
");continue;}
        ok=work();
        while(now<ln)//可能存在多个"第一层循环"
        {now++;ok=max(ok,work());}
        getf();//计算它给出的复杂度
        if(err) continue;
        if(ok!=fzd) printf("No
");
        if(ok==fzd) printf("Yes
"); 
    }
}

以上是关于luogu P3952 时间复杂度题解的主要内容,如果未能解决你的问题,请参考以下文章

[Luogu] P3952 时间复杂度

洛谷P3952 时间复杂度

LOJ P3952 时间复杂度 noip 暴力 模拟

P3952 时间复杂度

P3952 时间复杂度

P3952 时间复杂度