P2922 [USACO08DEC]秘密消息Secret Message

传送门

思路:

  还是比较水的(不看题解不看书),用 vis 存字典树上的每个点是多少个单词的前缀,bo 来存每个点是多少个单词的结尾(坑点:会有很多相同的单词,不能只有 bool 来存)。统计时:① 如果匹配串的长度小于单词的长度,ans+= vis;② 如果匹配串的长度≥单词长度,ans+=bo;③ 如果遇到字典树上的节点为空,直接返回。

标程:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<stack>
#include<vector>
#include<queue>
#include<deque>
#include<map>
#include<set>
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define maxn 500002
typedef long long LL;
LL n,m,len,cnt=0,ans=0;
LL a[maxn],ch[maxn][2],vis[maxn],bo[maxn];
inline LL read()
{
    LL kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(!(ls^45))
            kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return xs*kr;
}
inline void insert()
{
    LL u=0;
    for(LL i=1;i<=len;i++)
    {
        if(!ch[u][a[i]]) ch[u][a[i]]=++cnt;
        u=ch[u][a[i]];
        vis[u]++;
    }
    bo[u]++;
}
inline void find()
{
    LL u=0;
    for(LL i=1;i<=len;i++)
    {
        if(!ch[u][a[i]]) return;
        u=ch[u][a[i]];
        if(bo[u]&&i<len) ans+=bo[u];
    }
    ans+=vis[u];
}
int main()
{
    freopen("S.in","r",stdin);
    freopen("S.out","w",stdout);
    n=read();m=read();
    for(LL i=1;i<=n;i++)
    {
        len=read();
        for(LL j=1;j<=len;j++)
            a[j]=read();
        insert();
    }
    for(LL i=1;i<=m;i++)
    {
        ans=0;
        len=read();
        for(LL j=1;j<=len;j++)
            a[j]=read();
        find();
        printf("%lld\n",ans);
    }
return 0;
}

 

posted @ 2018-10-19 11:22  落笔映惆怅丶  阅读(176)  评论(0编辑  收藏  举报