luogu 3952 时间复杂度(模拟)

时间复杂度

这道题从两个月前开始做,一直没做出来,最后今晚决心一定要做出来。于是开始认真的在打草纸上写思路,最后在AC的那一刻,差点哭了出来!!

题目大意

这个自己看吧,noip2017的D1T2

solution

先介绍一下这道题我们用到的每个变量他们的用处

  1. stack[]记录变量的循环层
  2. vis[]记录变量在栈中是否出现过
  3. cmp函数,这个可以用作比较循环中a和b的大小
    \[
    \begin{cases}
    a<b -> 进入新的一层循环\a>b -> 无法进入新的循环,循环终止\a=b -> 此循环为o1
    \\end{cases}
    \]
  4. stop 如果循环已经无法进入,那么就用stop计数
  5. ans表示最终的复杂度层数,maxn表示当前一层循环的复杂度层数
    接下来是三种状态的
  6. ERR 条件
    \[
    \begin{cases}
    F、E不匹配\变量名重复
    \\end{cases}
    \]
  7. No,Yes均为题目定义

呼。然后就是代码了
首先你得会字符串处理一系列问题,如w,a,b之类的数字值,然后你得会普通的栈思想。

接下来第一步,我们如何处理复杂度问题。我的思路是分o1和on方的
o1你得判断他的循环层数不得为正整数,然后判一下ERR就可以了。
on方的话,你要准确判断他的循环层数

然后就是cmp函数,我的整段代码的精妙就全在cmp函数里了。
cmp函数判断的是a和b的值。
首先如果b不是n,那么他就不会形成一个循环层
其次如果数为n,那么就赋为inf
然后如果两个数如果都是数字,那么就为o1,直接按照相等处理
AC代码!

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int inf = 2147483647;
char s[200],a[200],b[200];
char stack[200];
char F,id;
int top;
bool vis[200],ERR;
int cmp(char *a,char *b) {
    int an=0,bn=0;
    if(a[0]=='n') an=inf;
    else {
        for(int i=0; i<strlen(a); i++)
            an=an*10+a[i]-'0';
    }
    if(b[0]=='n') bn=inf;
    else {
        for(int i=0; i<strlen(b); i++)
            bn=bn*10+b[i]-'0';
    }
    if(an>bn) return -1;
    if(an<bn && bn==inf) return 1;
    if(an==bn) return 0;
}
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        int n;
        memset(s,0,sizeof(s));
        memset(vis,0,sizeof(vis));
        memset(stack,0,sizeof(stack));
        top=0;
        scanf("%d",&n);
        cin >> s;
        int maxn=0,ans=0;
        int stop=0;
        ERR=false;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        if(s[2]=='1') {
            for(int i=1; i<=n; i++) {
                cin >> F;
                if(F=='E') {
                    if(stop)stop--;
                    vis[stack[top--]]=false;
                    if(top==0) {
                        ans=max(ans,maxn);
                        maxn=0;
                    }
                    if(top<0)ERR=true;
                } else if(F=='F') {
                    cin >> id;
                    if(vis[id]) ERR=true;
                    else vis[id]=1;
                    stack[++top]=id;
                    memset(a,0,sizeof(a));
                    memset(b,0,sizeof(b));
                    cin >> a >> b;
                    if(stop) {
                        stop++;
                        continue;
                    }
                    int flag=cmp(a,b);
                    if(flag==1) if(top>maxn)maxn++;
                    if(flag==-1) stop++;
                }
            }
            if(top || ERR) {
                printf("ERR\n");
                continue;
            }
            if(ans!=0) {
                printf("No\n");
                continue;
            }
            printf("Yes\n");
        }
        if(s[2]=='n') {
            int num=0;
            for(int i=0; i<strlen(s); i++)
                if(s[i]>='0'&&s[i]<='9')num=num*10+s[i]-'0';
            for(int i=1; i<=n; i++) {
                cin >> F;
                if(F=='E') {
                    if(stop)stop--;
                    vis[stack[top--]]=false;
                    if(top==0) {
                        ans=max(ans,maxn);
                        maxn=0;
                    }
                    if(top<0)ERR=true;
                } else if(F=='F') {
                    cin >> id;
                    if(vis[id]) ERR=true;
                    else vis[id]=1;
                    stack[++top]=id;
                    memset(a,0,sizeof(a));
                    memset(b,0,sizeof(b));
                    cin >> a >> b;
                    if(stop) {
                        stop++;
                        continue;
                    }
                    int flag=cmp(a,b);
                    if(flag==1) if(top>=maxn+1)maxn++;
                    if(flag==-1) stop++;
                }
            }
            if(top || ERR) {
                printf("ERR\n");
                continue;
            }
            if(ans!=num) {
                printf("No\n");
                continue;
            }
            printf("Yes\n");
        }
    }
    return 0;
}

tips:还有一件事请非常的重要,做模拟题之前,一定要理清思路,最好写在纸上,因为码量大的题目很容易会健忘,这样会有以思维时间换代码时间,垃圾思维大幅度缩短。

你会发现我曾经wa了无数发,都是没有认真思考的结果!

原文地址:https://www.cnblogs.com/ifmyt/p/9794846.html

时间: 2024-10-03 17:34:49

luogu 3952 时间复杂度(模拟)的相关文章

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,

【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标记 每做完一个程序,与前

[Luogu]5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III[分块]

题意 长为 \(n\) 的序列,询问区间众数,强制在线. \(n\leq 5\times 10^5\). 分析 考虑分块,暴力统计出整块到整块之间的众数次数. 然后答案还可能出现在两边的两个独立的块中,开 \(vector\) 记录每种数字出现的位置集合,然后暴力判断两边两个块中的元素出现的次数.发现并不需要知道具体在 \([l,r]\) 内出现了多少次,而只需要知道 \([l,r]\) 中是否有 \(ans+1\)个该种颜色. 总时间复杂度为 \(O(n\sqrt n)\). 代码 #incl

luogu P3952 时间复杂度题解

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

LUOGU P3161 [CQOI2012]模拟工厂 (贪心)

传送门 解题思路 贪心,首先因为\(n\)比较小,可以\(2^n\)枚举子集.然后判断的时候就每次看后面的如果用最大生产力生产能不能达成目标,解一个二次函数. 代码 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define int long long using namespace std; const int

Luogu P2827 蚯蚓(模拟)

P2827 蚯蚓 题意 题目描述 本题中,我们将用符号\(\lfloor c\rfloor\)表示对\(c\)向下取整,例如:\(\lfloor 3.0\rfloor =\lfloor 3.1\rfloor =\lfloor 3.9\rfloor =3\). 蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓. 蛐蛐国里现在共有\(n\)只蚯蚓(\(n\)为正整数).每只蚯蚓拥有长度,我们设第\(i\)只蚯蚓的长度为\(a_i(i=1,2,\dots

Luogu 考前模拟Round. 1

A.情书 题目:http://www.luogu.org/problem/show?pid=2264 赛中:sb题,直接暴力匹配就行了,注意一下读入和最后一句话的分句 赛后:卧槽 怎么只有40 B.小朋友的球 题目:http://www.luogu.org/problem/show?pid=1655 赛中:sb题,第二类斯特林数,加个高精度就行了,我还写了个暴力对拍 赛后:卧槽 怎么只有80 未知错误怎么回事儿啊 C.命运的彼方 题目:http://www.luogu.org/problem/s

[jzoj 6084] [GDOI2019模拟2019.3.25] 礼物 [luogu 4916] 魔力环 解题报告(莫比乌斯反演+生成函数)

题目链接: https://jzoj.net/senior/#main/show/6084 https://www.luogu.org/problemnew/show/P4916 题目: 题解: 我们设$f(x)$表示最小循环节长度为x的合法序列数,那么有$ans=\sum_{d|gcd(n,m)}\frac{1}{d}f(d)$ 这是因为最小循环节为d的序列对应的环会被计算d次,比如 0101,最小循环节长度为 2(循环节为 01),其对应的环会被统计 2 次(序列 0101 与 1010)

LUOGU P2564 [SCOI2009]生日礼物 (队列+模拟)

传送门 解题思路 还是比较好想的,用一个队列,然后把所有点放在一起排个序,依次入队.每次检查队头元素的种类是否为当前入队元素种类,是的话就一直\(pop\),每次更新答案即可. 代码 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std;