[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 调死我了 = =

浙公网安备 33010602011771号