[Trie树]BZOJ 1590 [Usaco2008 Dec]Secret Message 秘密信息 题解
题目大意
给出 n n 个01字符串a和个字符串b,求对于每个字符串b,有多少个字符串 a a 满足(lcp为最长公共前缀,min取长度较短的那个字符串), n,m≤105 n , m ≤ 10 5
解题报告
本以为是一道很难的题目,然后看了标程,就1**题。
其实只要在建Trie树时标两个数组sum和num,sum表示以这个节点为终点的字符串个数,num表示到达这个节点而且没完成的字符串个数,这样就不重复也不遗漏了。(我竟然傻到要建两棵Trie……)
就当是水Blog了……
示例代码
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,len,ch[500005][2],sum[500005],num[500005];
inline void readi(int &x){
x=0; char ch=getchar();
while ('0'>ch||ch>'9') ch=getchar();
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
void T_insist(){
int now=0,L; readi(L);
for (int i=1,x;i<=L;i++){
readi(x); if (!ch[now][x]) ch[now][x]=++len;
now=ch[now][x]; num[now]++;
}
num[now]--; sum[now]++;
}
int T_find(){
int now=0,L,ans=0,x; readi(L);
while(L--){
readi(x); if (ch[now][x]) now=ch[now][x];
else{
while (L--) readi(x);
return ans;
}
ans+=sum[now];
}
return ans+num[now];
}
int main()
{
freopen("message.in","r",stdin);
freopen("message.out","w",stdout);
readi(n); readi(m); len=0;
for (int i=1;i<=n;i++) T_insist();
for (int i=1;i<=m;i++) printf("%d\n",T_find());
return 0;
}