【BZOJ2754】[SCOI2012]喵星球上的点名

题面

bzoj

洛谷

题解

这题有各种神仙做法啊,什么暴力\(AC\)自动机、\(SAM\)等等五花八门

我这个蒟蒻在这里提供一种复杂度正确且常数小的做法。

根据后缀数组经典套路,

我们用一个未出现过的字符将所有串连接起来求一边\(SA\)(不算询问串)

然后因为我们现在已经将所有后缀排好序了

而询问串要有贡献一定是一个后缀的前缀

所以一个区间能产生贡献的后缀是排名连续的一段

这样这段区间的左右端点可以二分出来

我们再对于每个位置记一下它是哪一个人的

这样第一问就被转化成了区间内有多少种颜色,直接上莫队在排名上跑即可

到了这一步

第二问就很好做了

我们考虑差分,每新遇到一类数,我们加上剩余询问个数的贡献

每去掉一类数,减去剩余询问个数的贡献即可

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
inline int gi() { register int data = 0, w = 1; register char ch = 0; while (!isdigit(ch) && ch != '-') ch = getchar(); if (ch == '-') w = -1, ch = getchar(); while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); return w * data;
}
const int MAX_N = 2e5 + 5;
int N, n, m, a[MAX_N], id[MAX_N], lim = 1e4 + 5;
int sa[MAX_N];
void GetSA() {
#define cmp(i, j, k) (y[i] == y[j] && y[i + k] == y[j + k])static int x[MAX_N], y[MAX_N], bln[MAX_N];int M = lim; for (int i = 1; i <= N; i++) bln[x[i] = a[i]]++; for (int i = 1; i <= M; i++) bln[i] += bln[i - 1]; for (int i = N; i >= 1; i--) sa[bln[x[i]]--] = i; for (int k = 1; k <= N; k <<= 1) { int p = 0; for (int i = 0; i <= M; i++) y[i] = 0; for (int i = N - k + 1; i <= N; i++) y[++p] = i; for (int i = 1; i <= N; i++) if (sa[i] > k) y[++p] = sa[i] - k;for (int i = 0; i <= M; i++) bln[i] = 0; for (int i = 1; i <= N; i++) bln[x[y[i]]]++; for (int i = 1; i <= M; i++) bln[i] += bln[i - 1]; for (int i = N; i >= 1; i--) sa[bln[x[y[i]]]--] = y[i]; swap(x, y); x[sa[1]] = p = 1;for (int i = 2; i <= N; i++) x[sa[i]] = cmp(sa[i], sa[i - 1], k) ? p : ++p;if (p >= N) break;M = p; }
}
const int LEN = 400;
int cnt[MAX_N], bln[MAX_N];
struct Query { int l, r, id; } q[MAX_N]; int q_cnt = 0;
inline bool operator < (const Query &a, const Query &b) { if (bln[a.l] ^ bln[b.l]) return a.r < b.r; else return (bln[a.l] & 1) ? a.r < b.r : a.r > b.r;
}
int A1, ans1[MAX_N], ans2[MAX_N]; void add(int x, int pos) { cnt[id[sa[x]]]++; if (cnt[id[sa[x]]] == 1) ++A1, ans2[id[sa[x]]] += q_cnt - pos + 1;
}
void del(int x, int pos) { cnt[id[sa[x]]]--; if (cnt[id[sa[x]]] == 0) --A1, ans2[id[sa[x]]] -= q_cnt - pos + 1;
}
int main () {
#ifndef ONLINE_JUDGE freopen("cpp.in", "r", stdin);
#endif n = gi(), m = gi(); for (int i = 1, L; i <= n; i++) { L = gi(); for (int j = 1; j <= L; j++) a[++N] = gi(), id[N] = i; a[++N] = ++lim; L = gi(); for (int j = 1; j <= L; j++) a[++N] = gi(), id[N] = i; a[++N] = ++lim; } GetSA(); for (int i = 1; i <= m; i++) {int L = 1, R = N; for (int len = gi(), j = 1; j <= len; ++j) { int x = gi(), l = L, r = R; while (l <= r) {int mid = (l + r) >> 1; if (a[sa[mid] + j - 1] < x) l = mid + 1; else r = mid - 1; }int tmp = l; l = L, r = R; while (l <= r) { int mid = (l + r) >> 1; if (a[sa[mid] + j - 1] <= x) l = mid + 1; else r = mid - 1; } L = tmp, R = r; } if (L <= R) q[++q_cnt] = (Query){L, R, i}; } for (int i = 1; i <= N; i++) bln[i] = (i - 1) / LEN + 1; sort(&q[1], &q[q_cnt + 1]); for (int ql = 1, qr = 0, i = 1; i <= q_cnt; i++) { while (ql < q[i].l) del(ql, i), ++ql; while (ql > q[i].l) --ql, add(ql, i); while (qr < q[i].r) ++qr, add(qr, i); while (qr > q[i].r) del(qr, i), --qr;ans1[q[i].id] = A1; }for (int i = 1; i <= m; i++) printf("%d\n", ans1[i]); for (int i = 1; i <= n; i++) printf("%d ", ans2[i]); return 0;
} 

跑得还是挺快的,在洛谷跑了\(Rank4\)

转载于:https://www.cnblogs.com/heyujun/p/10305951.html

【BZOJ2754】[SCOI2012]喵星球上的点名相关推荐

  1. BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)

    Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...

  2. [BZOJ2754]-[SCOI2012]喵星球上的点名-AC自动机+树状数组

    说在前面 感觉这题还是挺经典的 所以还是写了记录一下- 题目 BZOJ2754传送门 洛谷P2336传送门 看题可进传送门 题目-略长,概括起来有点麻烦 解法 读完这道题之后,可以发现实际上它就是要我 ...

  3. [BZOJ2754][SCOI2012]喵星球上的点名(后缀数组+莫队)

    Address 洛谷P2336 BZOJ2754 LOJ#2374 Solution 考虑在每个人的姓和名之间插入一个无关的字符. 这样问题就转化成了一些主串和一些模式串,询问每个模式串能匹配到多少个 ...

  4. [BZOJ2754][SCOI2012]喵星球上的点名 后缀数组

    不科学啊...这题暴力可过...感觉所有串都是a就可以卡掉啊... 我的做法就是先把姓名串和询问串全部连在一起,并打上分隔符,并记录每个字符属于哪个串,求出SA.对于每个询问就从它所在的位置左右扫he ...

  5. bzoj2754: [SCOI2012]喵星球上的点名

    传送门 事实证明,我肉眼debug了两个晚上,还是不及对拍效率高. AC自动机写错了都毫不自觉的智障宸 因为数据水,写的暴力 //Achen #include<algorithm> #in ...

  6. 洛谷2336 BZOJ2754 SCOI2012 喵星球上的点名 SA 莫队 二分

    题目链接 题意: 有nnn个人,每个人有两个串,一个表示姓,一个表示名,这里用数字表示字符.有mmm次询问,对于每次询问,你要回答有多少个人的姓或者名至少有一个是给出的串的子串.最后再对于这nnn个人 ...

  7. BZOJ 2754: [SCOI2012]喵星球上的点名

    二次联通门 : BZOJ 2754: [SCOI2012]喵星球上的点名 /*BZOJ 2754: [SCOI2012]喵星球上的点名此题有N种做法...见到众dalao用各种奇怪的姿势AC此题..具 ...

  8. 洛谷 P2336 [SCOI2012]喵星球上的点名 解题报告

    P2336 [SCOI2012]喵星球上的点名 题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 \(N\) 个喵星人,每个喵星人的 ...

  9. SCOI2012 喵星球上的点名 BZOJ 2754

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 2246 Solved: 975 Description ...

最新文章

  1. s:property 获取 ValueStack中的值
  2. sql输出表中重复数据
  3. 2022-03-09
  4. CentOS下安装semanage
  5. ListView的Adapter使用(绑定数据) 之 自定义每一项的布局去绑定数据(二)
  6. java的input不能更改,无法将方法响应标头Content-Type更改为application / xml
  7. Python编程一定要注意的那些“坑”(九):0与False
  8. 浅谈 标准的代号和编号
  9. ANDROID 4.0 SDK R14 模拟器
  10. CSS代码实现背景透明文字不透明
  11. SpringBoot两种定时任务(Spring Schedule 与 Quartz 整合 )实现
  12. matlab help函数用法,MATLAB函数用法
  13. [译] 移动应用设计新趋势
  14. web前端人事面试常问问题
  15. python乌龟吃鱼_Python面向对象练习-通过pygame改良乌龟吃鱼
  16. 实验5 类的继承、派生和多态
  17. React Native 参考资料 (转自简书)
  18. wireshark学习笔记(MAC地址欺骗)
  19. Edge 浏览器 URLSearchParams bug 修复
  20. 前端,java后端开发,数据分析师应该掌握的技术,不要盲目跟风

热门文章

  1. python 捕捉 ctrl+c 异常方法, os._exit() 和 sys.exit() 的用法和区别
  2. cs224w(图机器学习)2021冬季课程学习笔记4 Link Analysis: PageRank (Graph as Matrix)
  3. project-clean的作用
  4. 零基础怎样系统的学习Python
  5. Caused by: java.lang.NullPointerException: Attempt to invoke virtual method ‘android.view.View andro
  6. Legacy引导转UEFI引导(BIOS、Legacy引导、UEFI引导、GPT/MBR分区)
  7. 【JSP/SERVLET】Tomcat内置表单身份验证
  8. Java使用百度地图API,根据地址,查询地址坐标。
  9. CIO应当牢记iPhone的七条安全建议
  10. B2B,B2C,C2C以及电子商务模式