【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\)

【BZOJ2754】[SCOI2012]喵星球上的点名的更多相关文章

  1. BZOJ2754: [SCOI2012]喵星球上的点名

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 680  Solved: 314[Submit][Sta ...

  2. [BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组

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

  3. bzoj2754:[SCOI2012]喵星球上的点名(后缀自动机)

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

  4. BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机)

    Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2816  Solved: 1246[Submit][Status][Discuss] Descript ...

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

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

  6. BZOJ2754 SCOI2012喵星球上的点名

    绝世好题. 正当我犹豫不决时,hzwer说:“MAP!!!” 没错这题大大的暴力,生猛的stl,贼基尔爽,,ԾㅂԾ,, 由于我们求点名在名字中的子串个数,所以将点名建AC自动机,记录节点属于哪次点名, ...

  7. BZOJ2754 [SCOI2012]喵星球上的点名 SA+莫队+树状数组

    题面 戳这里 题解 首先先把所有给出的姓名和询问全部接在一起,建出\(height\)数组. 某个串要包含整个询问串,其实就相当于某个串与询问串的\(lcp\)为询问串的长度. 而两个后缀\(Suff ...

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

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 649  Solved: 305[Submit][Sta ...

  9. BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][St ...

随机推荐

  1. python中执行shell命令

    查看输出结果 import os output = os.popen('cat 6018_gap_5_predict/solusion2/solusion2_0-1.txt | wc -l') pri ...

  2. 搞懂JVM类加载机制

    有这样一道面试题: class Singleton{ private static Singleton singleton = new Singleton(); public static int v ...

  3. 《Python核心编程》第二版第三章答案

    本人python新手,答案自己做的,如果有问题,欢迎大家评论和讨论! 更新会在本随笔中直接更新. 我在Windows使用python版本是2.7.0 3–10. 异常.使用类似readTextFile ...

  4. cocos2d-x开发:服务端基础库封装

    元旦前面几天都在忙着面试,随后的几天也就一直在做服务端基础库开发方面的工作.对于服务端开发,是很久之前的事情了.那时候我还在大学读书,一直都是在倒腾服务端开发方面的东西,毕业后参加公司工作就是一直从事 ...

  5. MySQL导出表结构方法

    方法一: 以下用的是Navicat Premium,可以换成任意图形化客户端 SELECT COLUMN_NAME 列名, COLUMN_TYPE 数据类型, DATA_TYPE 字段类型, CHAR ...

  6. eclipse删除的文件如何恢复。

    1.如果不小心删除了单个文件或者文件夹. 鼠标点击上级目录 Ctrl+z就可以恢复了. 如果没有恢复,就右击项目,选择Resore from Local History 然后选择你所删除的文件,选择恢 ...

  7. Java中的集合框架-Collection(一)

    一,Collection接口 在日常的开发工作中,我们经常使用数组,但是数组是有很多的局限性的,比如:数组大小固定后不可修改,只能存储基本类型的值等等. 基于数组的这些局限性,Java框架就产生了用于 ...

  8. ORM一对多查询

    现有两张表,一张书籍表(Book),一张作者表(Author) 现在想查询出书本信息和书本的作者 book=Book.objects.get(name="python") book ...

  9. 20181031noip模拟赛T1

    思路: 我们会发现不合法的位置只有两种情况 要么在前半边,要么在后半边 那么,我们将序列劈两次 使两次的长度分别为: (n为偶数时要特判一下,因为根本不可能) (n/2),(n/2+1) (n/2+1 ...

  10. 大数据学习之Hadoop运行模式

    一.Hadoop运行模式 (1)本地模式(默认模式): 不需要启用单独进程,直接可以运行,测试和开发时使用. (2)伪分布式模式: 等同于完全分布式,只有一个节点. (3)完全分布式模式: 多个节点一 ...