Secret Message G
题目大意
给定
题目分析
看到询问前缀,很容易想到对信息建立字典树。
规定字典树的左孩子代表
关于查询,需要进行分类讨论:
-
密码长度
> 信息长度 -
密码长度
< 信息长度
对于第一种情况,直接把路径上的所有节点的
对于第二种情况,可以考虑再增加一个
看代码理解吧:
#include<bits/stdc++.h>
using namespace std;
struct node{
int son[2],cnt,end;
}t[500001];//字典树
int a[10001],n,m,len,tot=1;
void add(int now,int x){//now 表示当前节点编号,x表示当前信息的编号
if(x>len)return;//长度溢出
if(t[now].son[a[x]])now=t[now].son[a[x]];//有孩子则跳转
else{//新建立子节点
t[now].son[a[x]]=++tot;//tot为当前节点数量
t[tot].son[0]=t[tot].son[1]=0;
now=tot;
}
t[now].cnt++;//累加cnt
if(x==len)t[now].end++;//最末尾则累加end
add(now,x+1);//进入下一层
}
void query(int now,int x,int ans){//ans表示最终答案,其余同上
if(t[now].son[a[x]])now=t[now].son[a[x]];
else{//此时密码长度较长,无法继续访问,进入情况1
printf("%d\n",ans);
return;
}
if(x==len){//密码遍历完,长度较短,进入情况2
printf("%d\n",ans+t[now].cnt);
return;
}
ans+=t[now].end;//ans累加
query(now,x+1,ans);
}
int main(){
scanf("%d%d",&m,&n);
while(m--){
scanf("%d",&len);
for(int i=1;i<=len;i++)scanf("%d",a+i);
add(1,1);//处理end、ans
}
while(n--){
scanf("%d",&len);
for(int i=1;i<=len;i++)scanf("%d",a+i);
query(1,1,0);//查询答案
}
return 0;
}
完结撒花!