>Description
奶牛共有M(1≤M≤50000)条二进制的消息,知道了第i条二进制信息的前bi(l《bi≤10000)位。
同时奶牛使用N(1≤N≤50000)条密码,我们仅仅了解第J条密码的前cj(1≤cj≤10000)位。
对于每条密码J,都可能有信息能够和它匹配。
匹配的标准是:第J条密码是第i条信息的前缀,或第i条信息是第J条密码的前缀。
答案输出每条密码能够与信息匹配的数量
在输入文件中,位的总数(即∑Bi+∑Ci)不会超过500000.
>Input
第1行:两个整数:M和N.
接下来M行:第i + 1行描述截取的代码i,其中包含整数b_i,表示信息长度,后跟b_i个由空格分隔的0和1
接下来N行:第M + j + 1行描述代码字j,其中包含整数c_ j,表示密码长度,后跟c_j个空格分隔的0和1
>Output
第1…N行:行j:第J条密码可以匹配的信息数。
>Sample Input
4 5
3 0 1 0
1 1
3 1 0 0
3 1 1 0
1 0
1 1
2 0 1
5 0 1 0 0 1
2 1 1
>Sample Output
1
3
1
1
2
>解题思路
终于做出来了
直接用字典树储存每条信息。储存过程中要记录pass与end,pass表示有多少条信息经过了这个点,end则为有多少条信息是在这个点结束的。
后枚举每条密码,用字典树进行查询:
1.每次加上当前的end(以信息为前缀)
2.如果密码还没有遍历完,但是下面没有“路”了,就直接输出(搜不下去了呗就推出)
3.如果密码遍历完了,答案减去当前的end再加上当前的pass(以密码为前缀)
标风优美
>代码
#include<iostream>
#include<cstdio>
using namespace std;
struct son //储存儿子
{
int s[2]; //s[0]为0儿子,s[1]为1儿子
} a[500005];
int n, m, c, t, now, ans, x[10005], end[500005], pass[500005];
int main()
{
scanf ("%d%d", &n, &m);
t = 1; //记录节点数
for (int i = 1; i <= n; i++)
{
now = 1;
scanf ("%d", &c);
for (int j = 1; j <= c; j++)
{
scanf ("%d", &x[j]);
if (a[now].s[x[j]] != 0) now = a[now].s[x[j]]; //如果有就直接转移
else
{
t++;
a[now].s[x[j]] = t;
now = t; //否则节点数++
}
pass[now]++;
}
end[now]++;
}
for (int i = 1; i <= m; i++)
{
now = 1;
ans = 0;
scanf ("%d", &c);
for (int j = 1; j <= c ; j++)
scanf ("%d", &x[j]);
for (int j = 1; j <= c ; j++)
{
now = a[now].s[x[j]]; //转移
if (now == 0) break;
ans += end[now];
if (j == c) ans = ans - end[now] + pass[now];
}
printf ("%d\n", ans);
}
return 0;
}