洛谷 P2336 [SCOI2012]喵星球上的点名
题目描述
a180285 幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。
假设课堂上有 N 个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M 个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。
然而,由于喵星人的字码过于古怪,以至于不能用 ASCII 码来表示。为了方便描述,a180285 决定用数串来表示喵星人的名字。
现在你能帮助 a180285 统计每次点名的时候有多少喵星人答到,以及 M 次点名结束后每个喵星人答到多少次吗?
输入输出格式
输入格式:
现在定义喵星球上的字符串给定方法:
先给出一个正整数 L ,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数 N 和 M。
接下来有 N 行, 每行包含第 i 个喵星人的姓和名两个串。 姓和名都是标准的喵星球上的字符串。
接下来有 M 行,每行包含一个喵星球上的字符串,表示老师点名的串。
输出格式:
对于每个老师点名的串输出有多少个喵星人应该答到。
然后在最后一行输出每个喵星人被点到多少次。
输入输出样例
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
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 */