题目大意:
分析:
以信息建立字典树,
求出所有信息作为暗号前缀,对暗号的贡献
再以暗号建立字典树
求出所有长于暗号的信息,对暗号的贡献
最后减去重复的情况,即信息完全等于暗号
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define N 50005
using namespace std;
struct Node {
int cnt, nxt[2];
}triea[N*10];
struct Code {
int cnt, nxt[2]; vector<int>num;
}trieb[N*10];
char s[60];
int aid[N], bid[N], ans[N], n, m, numa, numb;
vector<int>a[N], b[N];
void insert1(int now) {
int u = 0;
for (int i = 0; i < aid[now]; i++) {
int v = a[now][i];
if (!triea[u].nxt[v]) triea[u].nxt[v] = ++numa;
u = triea[u].nxt[v];
}
++triea[u].cnt;
}
void find1(int now) {
int u = 0;
for (int i = 0; i < bid[now]; i++) {
int v = b[now][i];
if (triea[u].nxt[v]) u = triea[u].nxt[v]; else break;
ans[now] += triea[u].cnt;
}
}
void insert2(int now) {
int u = 0;
for (int i = 0; i < bid[now]; i++) {
int v = b[now][i];
if (!trieb[u].nxt[v]) trieb[u].nxt[v] = ++numb;
u = trieb[u].nxt[v];
}
trieb[u].num.push_back(now);
}
void find2(int now) {
int u = 0;
for (int i = 0; i < aid[now]; i++) {
int v = a[now][i];
if (trieb[u].nxt[v]) u = trieb[u].nxt[v]; else break;
++trieb[u].cnt;
}
}
void deleterep(int now) {
int u = 0;
for (int i = 0; i < bid[now]; i++) {
int v = b[now][i];
if (!triea[u].nxt[v]) return; else u = triea[u].nxt[v];
}
ans[now] -= triea[u].cnt;
return;
}
int main() {
freopen("data.in", "r", stdin);
scanf("%d%d", &m, &n);
int x;
for (int i = 1; i <= m; i++) {
scanf("%d", &aid[i]);
for (int j = 1; j <= aid[i]; j++) scanf("%d", &x), a[i].push_back(x);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &bid[i]);
for (int j = 1; j <= bid[i]; j++) scanf("%d", &x), b[i].push_back(x);
}
for (int i = 1; i <= m; i++) insert1(i);
for (int i = 1; i <= n; i++) find1(i);
for (int i = 1; i <= n; i++) insert2(i);
for (int i = 1; i <= m; i++) find2(i);
for (int i = 1; i <= numb; i++)
for (int j = 0; j < trieb[i].num.size(); j++) ans[trieb[i].num[j]] += trieb[i].cnt;
for (int i = 1; i <= n; i++) deleterep(i), printf("%d\n", ans[i]);
}