洛谷 P5698 [CTSC1998]算法复杂度 题解

前言

咕了大半年,我回来了

说实话当鸽子的感觉挺不错???

原题链接

题意

给定一个伪代码,判断他总共需要进行几次操作,用多项式形式输出。

题解

首先,这是一道模拟题,发现性质的话比较水

输入及处理

对于 loopop

我们能够很容易的发现,对于任意的 loop 操作,与他有关的是在它上几层的 loop 以及在它下几层的 loopop,简单来说,整个伪代码可以看做一个一 begin 为根树形结构(暂时忽略 breakcontinue),以样例二为例,就像下图(忽略 breakcontinue

如此一来,我们只需要在读入时进行树形存储,最后扫描统计贡献就行

对于 breakcontinue

我们回忆一下 breakcontinue 的功能

  • break :结束本层循环
  • continue : 结束本次循环

很容易发现他们之间有几个共性

都只与本层循环有关,都改变了循环操作的对象,本层循环的剩余部分都变成了废话不会执行

那么对于 breakcontinue 操作,只需要忽略本层循环的剩余部分,对于 break , 再将循环次数改为1,就完成了对这两个操作的处理。用图表示就像下图(红色部分为发生变化的部分)

最终结构如下

因为题目没说总共有多少个 loopop 操作,所以存数据时最好用 vector指针 的方式存储,如下

点击查看代码
struct Node{ int val; //执行几次 bool leaf; //是否为叶节点,便于最后的统计 Node* father; //父节点是哪个 vector<Node> child; //子节点有哪些 }; Node root; while (1) { scanf ("%s", s + 1); if (s[1] == 'l') { scanf ("%s", s + 1); f -> child.push_back ((Node) {Change() % Mod, false, f}); //新建子节点 f = &f -> child.back(); //准备开始下一层循环 } else if (s[1] == 'o') { scanf ("%s", s + 1); f -> child.push_back ((Node) {Change() % Mod, true, f}); } else if (s[1] == 'b') { if (f == &root) continue; f -> val = 1, f = f -> father; //更改本层循环次数,并退回上一层循环 TillEnd(); //忽略本层循环后续部分 } else if (s[1] == 'c') { if (f == &root) continue; f = f -> father; TillEnd(); } else if (s[1] == 'e') { if (f == &root) break; //输入完毕 f = f -> father; } }
`

细心的大佬看官可以发现,loopop 以及 breakcontinue 的处理极其相似,这也是我将他们放到一起分析的原因

统计

因为之前已经存好了树形结构,统计的时候只需要递归进行,传递系数和指数即可

点击查看代码
int ans[N]; //ans_i表示n的i次方的系数 void dfs(Node u, int pow, int coe) { if (u.leaf) { ans[pow] = (ans[pow] + coe) % Mod, maxn = max(maxn, pow); return; } for (int i = 0; i < u.child.size(); ++i) (u.child[i].val == -1) ? dfs(u.child[i], pow + 1, coe % Mod) : dfs(u.child[i], pow, coe * u.child[i].val % Mod); }
点击查看代码

输出

从高到低输出即可,注意判系数为1及指数为1或0的情况

就下来是喜闻乐见的

全部代码

点击查看代码
#include<cstring> #include<cstdio> #include<vector> using namespace std; const int N = 20 + 10; const int Mod = 998244353; struct Node{ int val; bool leaf; Node* father; vector<Node> child; }; Node root; int ans[N]; char s[N]; int maxn; inline int read() { int s = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') s = (s << 3) + (s << 1) + (c ^ 48), c = getchar(); return s * f; } inline void write(int x) { if (x < 0) putchar('-'), x = ~(x - 1); int s[50], top = 0; while (x) s[++top] = x % 10, x /= 10; if (top == 0) s[++top] = 0; while (top) putchar(s[top--] + '0'); } inline int max(int x, int y) { return x > y ? x : y; } inline int Change() { if (s[1] == 'n') return -1; int n = strlen(s + 1), number = 0; for (int i = 1; i <= n; ++i) number = (number << 3) + (number << 1) + (s[i] ^ 48); if (number == 0) return -1; return number % Mod; } inline void TillEnd() { int cnt = 1; while (cnt) { scanf ("%s", s + 1); if (s[1] == 'l') ++cnt; else if (s[1] == 'e') --cnt; } } void dfs(Node u, int pow, int coe) { if (u.leaf) { ans[pow] = (ans[pow] + coe) % Mod, maxn = max(maxn, pow); return; } for (int i = 0; i < u.child.size(); ++i) (u.child[i].val == -1) ? dfs(u.child[i], pow + 1, coe % Mod) : dfs(u.child[i], pow, coe * u.child[i].val % Mod); } inline void print(int pos) { if (ans[pos] == 1) { if (pos == 0) printf ("1"); if (pos == 1) printf ("n"); if (pos >= 2) printf ("n^%d", pos); } else { if (pos == 0) printf ("%d", ans[pos]); if (pos == 1) printf ("%dn", ans[pos]); if (pos >= 2) printf ("%dn^%d", ans[pos], pos); } } int main() { root.val = 0, root.leaf = false, root.father = NULL; Node* f = &root; while (1) { scanf ("%s", s + 1); if (s[1] == 'l') { scanf ("%s", s + 1); f -> child.push_back ((Node) {Change() % Mod, false, f}); f = &f -> child.back(); } else if (s[1] == 'o') { scanf ("%s", s + 1); f -> child.push_back ((Node) {Change() % Mod, true, f}); } else if (s[1] == 'b') { if (f == &root) continue; f -> val = 1, f = f -> father; TillEnd(); } else if (s[1] == 'c') { if (f == &root) continue; f = f -> father; TillEnd(); } else if (s[1] == 'e') { if (f == &root) break; f = f -> father; } } dfs(root, 0, 1); print(maxn); for (int i = maxn - 1; i >= 0; --i) if (ans[i]) printf ("+"), print(i); printf ("\n"); return 0; }

P.S.

数据里有一个小锅,没注意会WA一个点,那就请各位看官自行去找喽~~


__EOF__

本文作者Nebula
本文链接https://www.cnblogs.com/Nebula-Astraea/p/16767326.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Nebula  阅读(219)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示