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

版权声明:本文为博主原创文章,欢迎转载。 https://blog.csdn.net/try__jhf/article/details/82147898

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

题目大意

给出 n 个01字符串a和 m 个字符串b,求对于每个字符串b,有多少个字符串 a 满足 l c p ( a , b ) = m i n ( a , b ) (lcp为最长公共前缀,min取长度较短的那个字符串), 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;
}

猜你喜欢

转载自blog.csdn.net/try__jhf/article/details/82147898
今日推荐