[Trie树]BZOJ 1590 [Usaco2008 Dec]Secret Message 秘密信息 题解

[Trie树]BZOJ 1590 [Usaco2008 Dec]Secret Message 秘密信息 题解

题目大意

给出 n n 个01字符串a和m个字符串b,求对于每个字符串b,有多少个字符串 a a 满足lcp(a,b)=min(a,b)(lcp为最长公共前缀,min取长度较短的那个字符串), n,m105 n , m ≤ 10 5

解题报告

本以为是一道很难的题目,然后看了标程,就1**题。

其实只要在建Trie树时标两个数组sum和num,sum表示以这个节点为终点的字符串个数,num表示到达这个节点而且没完成的字符串个数,这样就不重复也不遗漏了。(我竟然傻到要建两棵Trie……)

就当是水Blog了……

示例代码

BZOJ1590 LibreOJ10054

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值