[BZOJ2754][SCOI2012]喵星球上的点名
[BZOJ2754][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
数据规模及约定
对于30%的数据,保证:
1<=N,M<=1000,喵星人的名字总长不超过4000,点名串的总长不超过2000。
对于100%的数据,保证:
1<=N<=20000,1<=M<=50000,喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过10000。
题解
求后缀数组,对于每一次点名,点到的对应了一个区间,对于第一问就是问区间中有多少个不同的数,用个主席树就好了;对于第二问不会做,暴力骗过。。。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 300010 #define maxN 20010 #define maxM 50010 #define maxlog 19 #define maxnode 6000010 int n, m, Str[maxn], tag[maxn], lst[maxN], pre[maxn], st[maxM], Len[maxM], len; int rank[maxn], height[maxn], sa[maxn], Ws[maxn]; bool cmp(int* a, int p1, int p2, int l) { if(p1 + l > len && p2 + l > len) return a[p1] == a[p2]; if(p1 + l > len || p2 + l > len) return 0; return a[p1] == a[p2] && a[p1+l] == a[p2+l]; } void ssort() { int *x = rank, *y = height; int m = 0; for(int i = 1; i <= len; i++) Ws[x[i] = Str[i]]++, m = max(x[i], m); for(int i = 1; i <= m; i++) Ws[i] += Ws[i-1]; for(int i = len; i; i--) sa[Ws[x[i]]--] = i; for(int j = 1, pos = 0; pos < len; j <<= 1, m = pos) { pos = 0; for(int i = len - j + 1; i <= len; i++) y[++pos] = i; for(int i = 1; i <= len; i++) if(sa[i] > j) y[++pos] = sa[i] - j; for(int i = 1; i <= m; i++) Ws[i] = 0; for(int i = 1; i <= len; i++) Ws[x[i]]++; for(int i = 1; i <= m; i++) Ws[i] += Ws[i-1]; for(int i = len; i; i--) sa[Ws[x[y[i]]]--] = y[i]; swap(x, y); pos = 1; x[sa[1]] = 1; for(int i = 2; i <= len; i++) x[sa[i]] = cmp(y, sa[i], sa[i-1], j) ? pos : ++pos; } return ; } void calch() { for(int i = 1; i <= len; i++) rank[sa[i]] = i; for(int i = 1, j, k = 0; i <= len; height[rank[i++]] = k) for(k ? k-- : 0, j = sa[rank[i]-1]; Str[i+k] == Str[j+k]; k++); return ; } int Log[maxn], mnh[maxlog][maxn]; void rmq_init() { Log[1] = 0; for(int i = 2; i <= len; i++) Log[i] = Log[i>>1] + 1; for(int i = 1; i <= len; i++) mnh[0][i] = height[i]; for(int j = 1; (1 << j) <= len; j++) for(int i = 1; i + (1 << j) - 1 <= len; i++) mnh[j][i] = min(mnh[j-1][i], mnh[j-1][i+(1<<j-1)]); return ; } int query(int l, int r) { l++; if(l > r) return len - sa[r] + 1; int t = Log[r-l+1]; return min(mnh[t][l], mnh[t][r-(1<<t)+1]); } int ToT, rt[maxn], sumv[maxnode], lc[maxnode], rc[maxnode]; void update(int& y, int x, int l, int r, int p) { sumv[y = ++ToT] = sumv[x] + 1; if(l == r) return ; int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x]; if(p <= mid) update(lc[y], lc[x], l, mid, p); else update(rc[y], rc[x], mid + 1, r, p); return ; } int que(int o, int l, int r, int up) { if(r <= up) return sumv[o]; int mid = l + r >> 1, ans = que(lc[o], l, mid, up); if(up > mid) ans += que(rc[o], mid + 1, r, up); return ans; } int ask(int l, int r) { return que(rt[r], 0, len, l - 1) - que(rt[l-1], 0, len, l - 1); } int vis[maxM], hhh[maxN]; int main() { n = read(); m = read(); for(int i = 1; i <= n; i++) { int L = read(); while(L--) Str[++len] = read(), tag[len] = i; Str[++len] = 10001; L = read(); while(L--) Str[++len] = read(), tag[len] = i; Str[++len] = 10001; } for(int i = 1; i <= m; i++) { int L = read(); st[i] = len + 1; Len[i] = L; while(L--) Str[++len] = read(); Str[++len] = 10001; } ssort(); calch(); rmq_init(); /*for(int i = 1; i <= len; i++) printf("%d%c", Str[i], i < len ? ' ' : '\n'); for(int i = 1; i <= len; i++) printf("%d%c", sa[i], i < len ? ' ' : '\n'); for(int i = 1; i <= len; i++) printf("%d%c", tag[sa[i]], i < len ? ' ' : '\n'); for(int i = 1; i <= len; i++) printf("%d%c", height[i], i < len ? ' ' : '\n'); // */ for(int i = 1; i <= len; i++) pre[i] = lst[tag[sa[i]]], lst[tag[sa[i]]] = i; for(int i = 1; i <= len; i++) update(rt[i], rt[i-1], 0, len, pre[i]); for(int i = 1; i <= m; i++) { int now = rank[st[i]], l = 1, r = now, L, R; while(l < r) { int mid = l + r >> 1; if(query(mid, now) < Len[i]) l = mid + 1; else r = mid; } L = l; l = now; r = len + 1; while(r - l > 1) { int mid = l + r >> 1; if(query(now, mid) < Len[i]) r = mid; else l = mid; } R = l; // printf("%d [%d, %d]\n", now, L, R); printf("%d\n", ask(L, R) - 1); for(int j = L; j <= R; j++) if(tag[sa[j]] && vis[tag[sa[j]]] != i) vis[tag[sa[j]]] = i, hhh[tag[sa[j]]]++; } for(int i = 1; i <= n; i++) printf("%d%c", hhh[i], i < n ? ' ' : '\n'); return 0; }
真 TM 调死我了 = =