题目描述

阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机。打字机上只有 \(28\) 个按键,分别印有 \(26\) 个小写英文字母和 BP 两个字母。 经阿狸研究发现,这个打字机是这样工作的:

  • 输入小写字母,打字机的一个凹槽中会加入这个字母(按 P 前凹槽中至少有一个字母)。
  • 按一下印有 B 的按键,打字机凹槽中最后一个字母会消失。
  • 按一下印有 P 的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失(保证凹槽中至少有一个字母)。

例如,阿狸输入 aPaPBbP ,纸上被打印的字符如下:

  1. a
  2. aa
  3. ab

我们把纸上打印出来的字符串从 \(1\) 开始顺序编号,一直到 \(n\) 。打字机有一个非常有趣的功能,在打字机中暗藏一个带数字的小键盘,在小键盘上输入两个数 \((x,y)\) (其中 \(1 \le x,y \le n\) ),打字机会显示第 \(x\) 个打印的字符串在第 \(y\) 个打印的字符串中出现了多少次。

阿狸发现了这个功能以后很兴奋,他想写个程序完成同样的功能,你能帮助他么?

输入格式

输入的第一行包含一个字符串,按阿狸的输入顺序给出所有阿狸输入的字符。

第二行包含一个整数 \(m\) ,表示询问个数。 接下来 \(m\) 行描述所有由小键盘输入的询问。其中第i行包含两个整数 \(x, y\) ,表示第i个询问为 \((x, y)\) 。

输出格式

输出 \(m\) 行,其中第 \(i\) 行包含一个整数,表示第 \(i\) 个询问的答案。

样例

样例输入

  1. aPaPBbP
  2. 3
  3. 1 2
  4. 1 3
  5. 2 3

样例输出

  1. 2
  2. 1
  3. 0

数据范围与提示

所有测试数据的范围和特点如下表所示:

测试点编号 \(n\) 的规模 \(m\) 的规模 字符串长度 输入总长 (输入文件第一行的字符数)
1 $ 1\le n \le 100$ $ 1\le m \le 1000$ - \(\le 100\)
2 $ 1\le n \le 100$ $ 1\le m \le 1000$ - \(\le 100\)
3 $ 1\le n \le 1000$ $ 1\le m \le 10^4$ 单个长度 $ \le 1000$ ,总长度 $ \le 10^5$ \(\le 10^5\)
4 $ 1\le n \le 1000$ $ 1\le m \le 10^4$ 单个长度 $ \le 1000$ ,总长度 $ \le 10^5$ \(\le 10^5\)
5 $ 1\le n \le 10^4$ $ 1\le m \le 10^5$ 总长度 $ \le 10^5$ \(\le 10^5\)
6 $ 1\le n \le 10^4$ $ 1\le m \le 10^5$ 总长度 $ \le 10^5$ \(\le 10^5\)
7 $ 1\le n \le 10^4$ $ 1\le m \le 10^5$ 总长度 $ \le 10^5$ \(\le 10^5\)
8 $ 1\le n \le 10^5$ $ 1\le m \le 10^5$ - \(\le 10^5\)
9 $ 1\le n \le 10^5 $ $ 1\le m \le 10^5$ - \(\le 10^5\)
10 $ 1\le n \le 10^5$ $ 1\le m \le 10^5$ - \(\le 10^5\)

题解

一个比较直观的想法就是按照y来排序,然后对于所有y相同的x询问都只跑一次y,然后用个桶记录答案就可以了。这样能拿70分。

换一个方向来写,将Trie树上属于y的那条链搞上+1的标记,就转化成子树和的问题了,这个可以搞下来dfs序后用树状数组维护子树和。

但是注意处理dfs序的时候,连的边必须是该点的fail向该点连的边(这样才能匹配)。

那么在trie树上dfs一遍(不能是Trie图会进环),每次dfs到一个y的结尾,那么就把对应的x处理了(即查询x子树的区间)。

并且插入字符串要注意边读入边处理,不然读入完后每次重新处理一个串(如70分代码所示)光插入到Trie里面就TLE了...

70分代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define N 100010
  4. int ch[N][26], fail[N], last[N], q[N], val[N];
  5. int cnt = 0, tot = 0, num = 0;
  6. int vis[N], ans[N];
  7. char s[N];
  8. vector<char>st[N];
  9. struct Node {
  10. int x, y, id;
  11. }Q[N];
  12. void insert() {
  13. int u = 0; ++num;
  14. for(int i = 1; i <= cnt; ++i) {
  15. int c = s[i] - 'a';
  16. st[num].push_back(s[i]);
  17. if(!ch[u][c]) ch[u][c] = ++tot;
  18. u = ch[u][c];
  19. }
  20. val[u] = num;
  21. }
  22. bool cmp(Node a, Node b) {
  23. if(a.y == b.y) return a.x < b.x;
  24. return a.y < b.y;
  25. }
  26. void get_fail() {
  27. int l = 1, r = 1;
  28. for(int i = 0; i < 26; ++i) if(ch[0][i]) q[r++] = ch[0][i];
  29. while(l != r) {
  30. int u = q[l++];
  31. if(l == 100000) l = 1;
  32. for(int i = 0; i < 26; ++i) {
  33. if(ch[u][i]) {
  34. fail[ch[u][i]] = ch[fail[u]][i];
  35. q[r++] = ch[u][i];
  36. if(r == 100000) r = 1;
  37. } else ch[u][i] = ch[fail[u]][i];
  38. last[ch[u][i]] = val[fail[ch[u][i]]] ? fail[ch[u][i]] : last[fail[ch[u][i]]];
  39. }
  40. }
  41. }
  42. void query(int id) {
  43. for(int i = 1; i <= num; ++i) vis[i] = 0;
  44. int u = 0, len = st[id].size();
  45. for(int i = 0; i < len; ++i) {
  46. u = ch[u][st[id][i] - 'a'];
  47. for(int j = u; j; j = last[j]) {
  48. if(val[j]) vis[val[j]]++;
  49. }
  50. }
  51. }
  52. int main() {
  53. char c = getchar();
  54. while(c != '\n') {
  55. if(c == 'B') --cnt;
  56. else if(c == 'P') insert();
  57. else s[++cnt] = c;
  58. c = getchar();
  59. }
  60. int m;
  61. scanf("%d", &m);
  62. for(int i = 1, x, y; i <= m; ++i) {
  63. scanf("%d%d", &x, &y);
  64. Q[i] = (Node) {x, y, i};
  65. }
  66. sort(Q + 1, Q + m + 1, cmp);
  67. get_fail();
  68. for(int i = 1; i <= m; ++i) {
  69. if(Q[i].y != Q[i - 1].y) {
  70. query(Q[i].y);
  71. ans[Q[i].id] = vis[Q[i].x];
  72. } else ans[Q[i].id] = vis[Q[i].x];
  73. }
  74. for(int i = 1; i <= m; ++i) {
  75. printf("%d\n", ans[i]);
  76. }
  77. return 0;
  78. }

100分做法

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define N 100010
  4. int ch[N][26], fail[N], lst[N], val[N];
  5. int cnt = 0, tot = 0, n = 0;
  6. int ql[N], qr[N], ans[N];
  7. char s[N];
  8. struct Node {
  9. int x, y, id;
  10. }Q[N];
  11. struct edge {
  12. int to, nxt;
  13. }e[N];
  14. int head[N];
  15. inline void ins(int u, int v) {
  16. e[++cnt] = (edge) {v, head[u]};
  17. head[u] = cnt;
  18. }
  19. bool cmp(Node a, Node b) {
  20. if(a.y == b.y) return a.x < b.x;
  21. return a.y < b.y;
  22. }
  23. int q[N];
  24. inline void get_fail() {
  25. int l = 1, r = 1;
  26. for(int i = 0; i < 26; ++i) if(ch[0][i]) q[r++] = ch[0][i];
  27. while(l != r) {
  28. int u = q[l++];
  29. if(l == 100000) l = 1;
  30. for(int i = 0; i < 26; ++i) {
  31. if(ch[u][i]) {
  32. fail[ch[u][i]] = ch[fail[u]][i];
  33. q[r++] = ch[u][i];
  34. if(r == 100000) r = 1;
  35. } else ch[u][i] = ch[fail[u]][i];
  36. }
  37. }
  38. }
  39. int tim, dfn[N], low[N];
  40. int t[N][26], fa[N];
  41. void pre_dfs(int u) {
  42. dfn[u] = ++tim;
  43. for(int i = head[u]; i; i = e[i].nxt) pre_dfs(e[i].to);
  44. low[u] = tim;
  45. }
  46. int c[N];
  47. inline int lowbit(int x) { return x & -x; }
  48. inline void add(int x, int val) {
  49. for(int i = x; i <= tim; i += lowbit(i)) c[i] += val;
  50. }
  51. inline int query(int x) {
  52. int ans = 0;
  53. for(int i = x; i; i -= lowbit(i)) ans += c[i];
  54. return ans;
  55. }
  56. void dfs(int u) {
  57. add(dfn[u], 1);
  58. if(val[u])
  59. for(int i = ql[val[u]]; i <= qr[val[u]]; ++i)
  60. ans[Q[i].id] = query(low[lst[Q[i].x]]) - query(dfn[lst[Q[i].x]] - 1);
  61. for(int i = 0; i < 26; ++i) if(t[u][i]) dfs(t[u][i]);
  62. add(dfn[u], -1);
  63. }
  64. int main() {
  65. int u = 0;
  66. char c = getchar();
  67. while(c != '\n') {
  68. if(c >= 'a' && c <= 'z') {
  69. if(!ch[u][c - 'a']) ch[u][c - 'a'] = ++tot, fa[tot] = u;;
  70. u = ch[u][c - 'a'];
  71. }
  72. if(c == 'B') u = fa[u];
  73. if(c == 'P') lst[++n] = u, val[u] = n;
  74. c = getchar();
  75. }
  76. int m;
  77. scanf("%d", &m);
  78. for(int i = 1, x, y; i <= m; ++i) {
  79. scanf("%d%d", &x, &y);
  80. Q[i] = (Node) {x, y, i};
  81. }
  82. sort(Q + 1, Q + m + 1, cmp);
  83. for(int i = 0; i <= tot; ++i)
  84. for(int j = 0; j < 26; ++j) t[i][j] = ch[i][j];
  85. get_fail(); cnt = 0;
  86. for(int i = 1; i <= tot; ++i) ins(fail[i], i);
  87. pre_dfs(0);
  88. for(int i = 1, p = 1; i <= m; i = p) {
  89. ql[Q[i].y] = i;
  90. while(Q[p].y == Q[i].y) ++p;
  91. qr[Q[i].y] = p - 1;
  92. }
  93. dfs(0);
  94. for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
  95. return 0;
  96. }

LOJ#2444. 「NOI2011」阿狸的打字机的更多相关文章

  1. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  2. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  3. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  4. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  5. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  6. Loj #3059. 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

  7. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

  8. Loj #3055. 「HNOI2019」JOJO

    Loj #3055. 「HNOI2019」JOJO JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 ...

  9. Loj 3058. 「HNOI2019」白兔之舞

    Loj 3058. 「HNOI2019」白兔之舞 题目描述 有一张顶点数为 \((L+1)\times n\) 的有向图.这张图的每个顶点由一个二元组 \((u,v)\) 表示 \((0\le u\l ...

随机推荐

  1. 重建二叉树POJ2255

    重建二叉树 给定一棵二叉树的前序遍历和中序遍历的结果,求其后序遍历. 输入输入可能有多组,以EOF结束.每组输入包含两个字符串,分别为树的前序遍历和中序遍历.每个字符串中只包含大写字母且互不重复.输出 ...

  2. 转:安装PHP出现make: *** [sapi/cli/php] Error 1 解决办法

    ext/iconv/.libs/iconv.o: In function `php_iconv_stream_filter_ctor':/home/king/PHP-5.2.13/ext/iconv/ ...

  3. 关于JS的几个基础题目

    1.截取字符串abcdefg的efg alert("abcdefg".substring(4)); 2.判断一个字符串中出现次数最多的字符,统计这个次数 var str = 'as ...

  4. AtCoder Beginner Contest 045 C - たくさんの数式 / Many Formulas

    Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem Statement You are given a string ...

  5. jdbc --例子7

    package cn.kitty.o1; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLE ...

  6. SRTP参数及数据包处理过程(转)

    源: SRTP参数及数据包处理过程

  7. 使用Selenium+firefox抓取网页指定firefox_profile后的问题

    from: https://blog.csdn.net/chufazhe/article/details/51145834 摘要:在使用selenium和firefox抓取网页指定firefox_pr ...

  8. Mysql去掉html标签函数

    函数 SET GLOBAL log_bin_trust_function_creators=; DROP FUNCTION IF EXISTS fnStripTags; DELIMITER | CRE ...

  9. JVM优化-JVM参数配置

    配置方式: java [options] MainClass [arguments] options - JVM启动参数. 配置多个参数的时候,参数之间使用空格分隔. 参数命名: 常见为 -参数名 参 ...

  10. Spring Boot 2 (四):使用 Docker 部署 Spring Boot

    Spring Boot 2 (四):使用 Docker 部署 Spring Boot Docker 技术发展为微服务落地提供了更加便利的环境,使用 Docker 部署 Spring Boot 其实非常 ...