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\n");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\n");continue;}
        ok=work();
        while(now<ln)//可能存在多个"第一层循环"
        {now++;ok=max(ok,work());}
        getf();//计算它给出的复杂度
        if(err) continue;
        if(ok!=fzd) printf("No\n");
        if(ok==fzd) printf("Yes\n");
    }
}

原文地址:https://www.cnblogs.com/lcez56jsy/p/12181186.html

时间: 2024-09-29 03:25:48

luogu P3952 时间复杂度题解的相关文章

【luogu P3952 时间复杂度】题解

对于2017 D1 T2 这道题 实实在在是个码力题,非常考验耐心. 其实大体的思路并不是非常难想出来,但是要注意的小细节比较多. 题目链接:https://www.luogu.org/problemnew/show/P3952 思路 对于每一个程序,先读入L和O(),并将其中的时间复杂度抠出来. 其次整行读入字符串,即所给定的程序. 判断第一个字符是F or E F i x y 需要把x y拿出来,把i压进栈 E 退栈 压进i后为了方便退栈及退栈时判断,用一个flag标记 每做完一个程序,与前

洛谷P3952 时间复杂度

题目:https://www.luogu.org/problemnew/show/3952 题目描述 小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序, 于是你的机会来啦!下面请你编写程序来判断小明对他的每个程序给出的时间复杂度是否正确. A++语言的循环结构如下: F i x y 循环体 E 其中F i x y表示新建变量 i(变量 i 不可与未被销毁的变量重名)并初始化为 x, 然后判断 

邮递员送信(luogu 1629)题解

[问题描述] 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间.这个邮递员每次只能带一样东西.求送完这N-1样东西并且最终回到邮局最少需要多少时间. [样例输入] 5 10    2 3 5    1 5 5    3 5 6    1 2 8    1 3 8    5 3 4    4 1 8    4 5 3    3 5 6    5 4 2 [样例输出] 83

luogu 3952 时间复杂度

noip2017 D1T2 某zz选手考场上写了1.5h 考完之后发现自己写的是错的 但是结果A了??? 题目大意: 一种新的编程语言 A++ 给出一个程序只有循环语句 并给出这个程序的时间复杂度 判断每个程序给出的时间复杂度是否正确. A++语言的循环结构如下: F i x y 循环体 E 其中F i x y表示新建变量i(变量i不可与未被销毁的变量重名)并初始化为 x 然后判断 i 和 y 的大小关系,若 i 小于等于 y 则进入循环 否则不进入 每次循环结束后 i 都会被修改成 i +1,

洛谷 P3952 时间复杂度

做这道题的最大收获就是坚持不懈,勇往直前,这道题是一个"码力题",不能说无脑,但绝对恶心.总共花了3h+才调出来.果然当时NOIp放弃这道题是明智的 好了,闲话放一边,我们来搞一搞这道题. 这道题思路很简单,就是模拟.t<=10和L<=100也提示了我们时间不是问题,要大胆的去模拟.我是在线判断程序是否ERR,离线判断时间复杂度计算是否正确.如果程序ERR,就标记一下,输入完之后直接结束这次循环(continue),不再进行接下来的计算.至于判断Yes和No,我先将输入的时

luogu 3952 时间复杂度(模拟)

时间复杂度 这道题从两个月前开始做,一直没做出来,最后今晚决心一定要做出来.于是开始认真的在打草纸上写思路,最后在AC的那一刻,差点哭了出来!! 题目大意 这个自己看吧,noip2017的D1T2 solution 先介绍一下这道题我们用到的每个变量他们的用处 stack[]记录变量的循环层 vis[]记录变量在栈中是否出现过 cmp函数,这个可以用作比较循环中a和b的大小 \[ \begin{cases} a<b -> 进入新的一层循环\a>b -> 无法进入新的循环,循环终止\

Luogu P1342 请柬 题解

差不多是Dijkstra的裸题吧... 这道题可以分为来回两个阶段. 去的时候很简单,直接用一次Dijkstra,然后统计答案. 回来的时候就有些巧妙了,虽然表面上是每个点回到起点,但是何尝不可将其看成从起点出发,逆着每个点过来的路去找一次每个点?所以只需要存边的时候处理一下,然后直接跑Dijkstra就行了. 附上代码. #include<bits/stdc++.h> #define clean(a,i) memset(a,i,sizeof(a)) #define ll long long

Luogu P4014 分配问题 题解

闲扯 蒟蒻的第一道自己想出怎么建图的题!!虽然是一个没什么技术含量的图 想了想,还是写篇题解纪念一下. 题面 题面 Solution 要求最小费用和最大费用,同时限制了流量,考虑费用流. 虚拟一个超级源点,从这个点分别向 \(N\) 个任务连一条流量为 \(1\) ,费用为 \(0\) 的边. 虚拟一个超级汇点,才从 \(N\) 个物品分别向该点连一条流量为 \(1\) ,费用为 \(0\) 的边. 因为每个人只能做一件,且每个工作只能做一次,所以连的边流量都为一.而第 \(i\) 个人做第 \

P3952 时间复杂度

—————————————————————————————————————————————————— noip罕见的纯模拟题,细节还是很多的 虽然没有看题解,但也错了很多地方 1,Yes与YES 2,ERR与Err,这个真的毒瘤,一个全大写一个却不是 3,ERR后向栈中添加元素防止RE 4,最后判断栈空. ————————————————————————————————————————- #include<bits/stdc++.h> using namespace std; int t,ln