【题意】:
贝茜正在领导奶牛们逃跑。为了联络,奶牛们互相发送秘密信息。
信息是二进制的,共有 M 条。反间谍能力很强的约翰已经部分拦截了这些信息,知道了第 i 条二进制信息的前 bi 位。他同时知道,奶牛使用 N 条密码。但是,他仅仅了解第 j 条密码的前 cj位。
对于每条密码 j ,他想知道有多少截得的信息能够和它匹配。也就是说,有多少信息和这条密码有着相同的前缀。当然,这个前缀长度必须等于密码和那条信息长度的较小者。
【思路】:先对截获的信息建一颗Trie字典树,同时维护以下几个值:
1、is_end[u]:表示是否有单词以编号为u的节点为结束符
2、b[u]:表示有多少个单词经过编号为u的节点
那么统计变得简单:在对密码进行遍历字典树时,如果is_end[u]==true,那么答案个数+1,最后返回答案个数+b[u]
#include
using namespace std;
const int N=5e5+3e2;
int ch[N][2],tot,b[N];
int n,m,l,i,s[11000],j;
bool is_end[N];
inline void insert(int l){
register int i,u=0;
for(i=1;i<=l;i++){
register int c=s[i];
if (ch[u][c]==-1)
ch[u][c]=++tot;
u=ch[u][c];b[u]++;
}
is_end[u]++;
}
inline int query(int l){
register int cnt=0,u=0;
for(int i=1;i<=l;i++){
register int c=s[i];
if (ch[u][c]==-1)
return cnt;
// 无法匹配,直接返回
u=ch[u][c];
cnt+=is_end[u];
// 别人是它的前缀
}
return cnt+b[u];//它是别人的前缀
}
int main(){
freopen("t1.in","r",stdin);
memset(ch,-1,sizeof(ch));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&l);
for(j=1;j<=l;j++)
scanf("%d",&s[j]);
insert(l);
}
for(i=1;i<=m;i++){
scanf("%d",&l);
for(j=1;j<=l;j++)
scanf("%d",&s[j]);
printf("%d\n",query(l));
}
return 0;
}
但是,我们发现以上代码连样例都过不了,为什么?
如图(用鼠标画的,有点丑),黑线表示边,黑色数字表示边上的字符,红色数字表示有多少个信息以该节点结尾,蓝色数字表示有多少个数字经过该节点,我们发现,当我们查询密码为“1”时,本来答案是3(“1”,“11”,“101”),但输出是4,为什么?因为在节点1处重复统计了!
怎么办?很简单,对于is_end[u]=true的节点u,b[u]--即可AC
//The AC code by hpwwzyy2012
#include
using namespace std;
const int N=5e5+3e2;
int ch[N][2],tot,b[N];
int n,m,l,i,s[11000],j;
bool is_end[N];
inline void insert(int l){
register int i,u=0;
for(i=1;i<=l;i++){
register int c=s[i];
if (ch[u][c]==-1)
ch[u][c]=++tot;
u=ch[u][c];b[u]++;
}
is_end[u]++;b[u]--;
}
inline int query(int l){
register int cnt=0,u=0;
for(int i=1;i<=l;i++){
register int c=s[i];
if (ch[u][c]==-1)
return cnt;
// 无法匹配,直接返回
u=ch[u][c];
cnt+=is_end[u];
// 别人是它的前缀
}
return cnt+b[u];//它是别人的前缀
}
int main(){
freopen("t1.in","r",stdin);
memset(ch,-1,sizeof(ch));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&l);
for(j=1;j<=l;j++)
scanf("%d",&s[j]);
insert(l);
}
for(i=1;i<=m;i++){
scanf("%d",&l);
for(j=1;j<=l;j++)
scanf("%d",&s[j]);
printf("%d\n",query(l));
}
return 0;
}