洛谷 P2336 [SCOI2012]喵星球上的点名

题目描述

a180285 幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。

假设课堂上有 N 个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M 个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。

然而,由于喵星人的字码过于古怪,以至于不能用 ASCII 码来表示。为了方便描述,a180285 决定用数串来表示喵星人的名字。

现在你能帮助 a180285 统计每次点名的时候有多少喵星人答到,以及 M 次点名结束后每个喵星人答到多少次吗?

输入输出格式

输入格式:

现在定义喵星球上的字符串给定方法:

先给出一个正整数 L ,表示字符串的长度,接下来L个整数表示字符串的每个字符。

输入的第一行是两个整数 N 和 M。

接下来有 N 行, 每行包含第 i 个喵星人的姓和名两个串。 姓和名都是标准的喵星球上的字符串。

接下来有 M 行,每行包含一个喵星球上的字符串,表示老师点名的串。

输出格式:

对于每个老师点名的串输出有多少个喵星人应该答到。

然后在最后一行输出每个喵星人被点到多少次。

输入输出样例

输入样例#1:

2 3
6 8 25 0 24 14 8 6 18 0 10 20 24 0
7 14 17 8 7 0 17 0 5 8 25 0 24 0
4 8 25 0 24
4 7 0 17 0
4 17 0 8 25

输出样例#1:

2
1
0
1 2

说明

事实上样例给出的数据如果翻译成地球上的语言可以这样来看

2 3

izayoi sakuya

orihara izaya

izay hara raiz

对于 30%的数据,保证:

1<=N,M<=1000,喵星人的名字总长不超过 4000,点名串的总长不超过 2000,

对于 100%的数据,保证:

1<=N<=20000 ,1<=M<=50000. 喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过 10000

题目大意:多个模板串多个匹配串,求每个模板串被匹配了多少次,每个匹配串匹配了多少模板,字符集很大

要命题,调了一下午

AC自动机的最坏复杂度是n^2,然而这题没有卡,可以过

后缀数组+ST表+二分+莫队+差分

首先把这么一大堆东西串起来,像这样

izayoi#sakuya#orihara#izaya#izay#hara#raiz#

具体实现的话所有字符+1,0充当分隔符就好了

然后对每一个名字所占据的位置记录一下颜色,像这样

izayoi#sakuya#orihara#izaya#izay#hara#raiz#
1111111111111122222222222222000000000000000

记录一下每一个点名的起点和长度

然后把sa和height求出来

先搞定每个匹配串匹配多少模板,把height的ST表搞出来,二分一下height>点名长度的区间,这个区间的中间位置大概在rank[点名起点],但也可能是个空区间,需要特判一下

然后就问题变成了区间颜色个数,莫队模板题

然后处理每个模板串被多少匹配串匹配过

做一个差分,每次在莫队添加和删除元素的时候,如果把一种颜色删光了,给这种颜色的出现次数减去剩下的询问数量,如果一种颜色新出现了,加上剩下的询问数量

  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <algorithm>
  5 #include <string>
  6 #include <cstring>
  7 #include <cmath>
  8 #include <map>
  9 #include <stack>
 10 #include <set>
 11 #include <vector>
 12 #include <queue>
 13 #include <time.h>
 14 #define eps 1e-7
 15 #define INF 0x3f3f3f3f
 16 #define MOD 1000000007
 17 #define rep0(j,n) for(int j=0;j<n;++j)
 18 #define rep1(j,n) for(int j=1;j<=n;++j)
 19 #define pb push_back
 20 #define mp make_pair
 21 #define set0(n) memset(n,0,sizeof(n))
 22 #define ll long long
 23 #define ull unsigned long long
 24 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt)
 25 #define max(a,b) (((a)>(b))?(a):(b))
 26 #define min(a,b) (((a)<(b))?(a):(b))
 27 #define print_runtime printf("Running time:%.3lfs\n",double(clock())/1000.0)
 28 #define TO(j) printf(#j": %d\n",j);
 29 //#define OJ
 30 using namespace std;
 31 const int MAXINT = 401000;
 32 const int MAXNODE = 100010;
 33 const int MAXEDGE = 2 * MAXNODE;
 34 char BUF, *buf;
 35 int read() {
 36     char c = getchar(); int f = 1, x = 0;
 37     while (!isdigit(c)) { if (c == ‘-‘) f = -1; c = getchar(); }
 38     while (isdigit(c)) { x = x * 10 + c - ‘0‘; c = getchar(); }
 39     return f * x;
 40 }
 41 char get_ch() {
 42     char c = getchar();
 43     while (!isalpha(c)) c = getchar();
 44     return c;
 45 }
 46 //------------------- Head Files ----------------------//
 47 int cnt_qr, sa[MAXINT], rk[MAXINT], trk[MAXINT], height[MAXINT], tsa[MAXINT], tstr[MAXINT], cnt[MAXINT], len, s[MAXINT], n, m, color[MAXINT];
 48 int st[18][MAXINT], maxp[MAXINT*2], ans=0, cnt_c[50010], cnt_miao[20010], rp;
 49 pair<int, int> qr[50010];
 50 struct query {
 51     int l, r, id;
 52     query() {}
 53     query(int _l, int _r, int _id) : l(_l), r(_r), id(_id) {}
 54 } mo[MAXINT];
 55 bool operator < (const query &a, const query &b) {
 56     return (a.l / 447 == b.l / 447) ? a.r < b.r : (a.l / 447 < b.l / 447);
 57 }
 58 int cmp(int *a, int p1, int p2, int l) {
 59     return a[p1] == a[p2] && a[p1 + l] == a[p2 + l];
 60 }
 61 void get_st() {
 62     rep0(i, 18) {
 63         for (int j = (1 << i); j < (1 << (i + 1)); j++) maxp[j] = i;
 64     }
 65     rep0(i, len) st[0][i] = height[i];
 66     rep1(i, 17) rep0(j, len - (1 << i) + 1) st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
 67 }
 68 int gt(int l, int r) { //[l,r]
 69     int pw = maxp[r - l + 1];
 70     return min(st[pw][l], st[pw][r - (1 << pw) + 1]);
 71 }
 72 void get_sa() {
 73     int i, j, k, sz = MAXINT;
 74     for (i = 0; i < sz; i++) cnt[i] = 0;
 75     for (i = 0; i < len; i++) cnt[trk[i] = s[i]]++;
 76     for (i = 1; i < sz; i++) cnt[i] += cnt[i - 1];
 77     for (i = len - 1; i >= 0; i--) sa[--cnt[s[i]]] = i;
 78     for (j = 1, k = 1; k < len; j <<= 1, sz = k) {
 79         for (k = 0, i = len - j; i < len; i++) tsa[k++] = i;
 80         for (i = 0; i < len; i++) if (sa[i] >= j) tsa[k++] = sa[i] - j;
 81         for (i = 0; i < len; i++) tstr[i] = trk[tsa[i]];
 82
 83         for (i = 0; i < sz; i++) cnt[i] = 0;
 84         for (i = 0; i < len; i++) cnt[tstr[i]]++;
 85         for (i = 1; i < sz; i++) cnt[i] += cnt[i - 1];
 86         for (i = len - 1; i >= 0; i--) sa[--cnt[tstr[i]]] = tsa[i];
 87         for (swap(tsa, trk), k = 1, trk[sa[0]] = 0, i = 1; i < len; i++) {
 88             trk[sa[i]] = cmp(tsa, sa[i], sa[i - 1], j) ? k - 1 : k++;
 89         }
 90     }
 91 }
 92 void get_height() {
 93     int i, j, k;
 94     for (i = 0; i < len; i++) rk[sa[i]] = i;
 95     for (i = 0, k = 0; i < len - 1; height[rk[i++]] = k) {
 96         for (k ? k-- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k++);
 97     }
 98 }
 99 query get_query(int id) {
100     int pos = rk[qr[id].first], l = qr[id].second;
101     query ret; ret.id = id;
102     if (pos == len - 1) pos = pos + 1;
103     else {
104         if (height[pos] < l) pos = pos + 1;
105     }
106     if (height[pos] < l) return query(-1, -1, -1);
107     int mid, lb = pos, rb = len;
108     while (rb - lb > 1) {
109         mid = (lb + rb) / 2;
110         if (gt(pos, mid) < l) rb = mid; else lb = mid;
111     }
112     ret.r = lb;
113     lb = 0; rb = pos;
114     while (rb - lb > 1) {
115         mid = (lb + rb) / 2;
116         if (gt(mid, pos) < l) lb = mid; else rb = mid;
117     }
118     ret.l = rb - 1;
119     return ret;
120 }
121 void get_input();
122 void work();
123 void append() {
124     int l = read();
125     rep0(i, l) {
126         int w = read();
127         s[len++] = w + 1;
128     }
129     s[len++] = 0;
130 }
131 void add(int v) {
132     cnt[v]++;
133     if (v != 0 && cnt[v] == 1) {
134         ans++;
135         cnt_miao[v] += cnt_qr - rp;
136     }
137 }
138 void del(int v) {
139     cnt[v]--;
140     if (v!=0 && cnt[v] == 0) {
141         ans--;
142         cnt_miao[v] -= cnt_qr - rp;
143     };
144 }
145 int main() {
146     get_input();
147     work();
148     return 0;
149 }
150 void work() {
151     get_sa();
152     get_height();
153     get_st();
154     rep0(i, m) {
155         mo[cnt_qr] = get_query(i);
156         if (mo[cnt_qr].id != -1) cnt_qr++;
157     }
158     sort(mo, mo + cnt_qr);
159     memset(cnt, 0, sizeof(cnt));
160     int l = 0, r = -1;
161     for (rp = 0; rp < cnt_qr; rp++) {
162         for (; l < mo[rp].l; del(color[sa[l]]), l++);
163         for (; l > mo[rp].l; l--, add(color[sa[l]]));
164         for (; r > mo[rp].r; del(color[sa[r]]), r--);
165         for (; r < mo[rp].r; r++, add(color[sa[r]]));
166         cnt_c[mo[rp].id] = ans; l = mo[rp].l; r = mo[rp].r;
167     }
168     rep0(i, m) printf("%d\n", cnt_c[i]);
169     rep1(i, n) printf("%d ", cnt_miao[i]);
170     putchar(‘\n‘);
171 }
172 void get_input() {
173     n = read(); m = read();
174     int l;
175     rep1(i, n) {
176         int p = len;
177         append(); append();
178         for (int j = p; j < len; j++) color[j] = i;
179     }
180     rep0(i, m) {
181         int p = len;
182         append();
183         for (int j = p; j < len; j++) color[j] = 0;
184         qr[i] = make_pair(p, len - p - 1);
185     }
186 }
187 /*
188 2 1
189 2 2 1 1 1
190 2 2 1 1 1
191 2 2 1
192 */
时间: 2024-10-05 15:46:56

洛谷 P2336 [SCOI2012]喵星球上的点名的相关文章

P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队)

P2336 [SCOI2012]喵星球上的点名 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> #define rint register int using namespace std; int read(){ char c=getchar();int x=0; while(

luogu P2336 [SCOI2012]喵星球上的点名

传送门 这题tm把AC自动机叉掉了,,, 只能考虑别的做法 把所有串连在一起,不同串的交界处加入一些不同的字符,然后求出sa数组和height数组,现在一个询问的答案就是和那个询问串的lcp正好为询问串长度的原串个数,而这在把后缀排好序后是一个区间,每个原串答案为包含这个原串的某个点的区间个数 如果将每个原串的点染成对应编号的颜色,那么现在求的是每个区间包含的点的颜色种类和每种点被多少个区间包含,可以用莫队实现,前者就是HH的项链,后者可以在每种颜色对第一种答案加上贡献时对其答案加上剩余询问个数

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

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

BZOJ 2754([SCOI2012]喵星球上的点名-后缀数组统计序列集合中子序列出现次数)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 805  Solved: 380 [Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,

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

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1926  Solved: 850[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这

bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1359  Solved: 618[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

bzoj2754 [SCOI2012]喵星球上的点名 (后缀数组+树状数组)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 2745 Solved: 1190 [Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么

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

a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到. 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示.为了方便描述,a180285决定用数串来表示喵星人的名字. 现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?

BZOJ 2754 SCOI2012 喵星球上的点名 fail树+set启发式合并

题目大意:给定n个目标串和m个模式串,问这m个模式串每个在多少个目标串中出现过,以及n个目标串每个以最多多少个模式串为子串 我错了--就算用fail树+set启发式合并也优化不到O(nlog^2n)--这题的数据范围相当无解啊 首先将所有名字和点名的字符串全都插进AC自动机 将每个点上开一个set记录这个点是哪些喵星人的名字的前缀 然后建立fail树 沿着fail树从下到上启发式合并 每合并完一个点 如果这个点是某次点名的字符串 那么这次点名点到的喵星人就是这个点的set中的所有元素 统计答案即