• Secret Message 秘密信息


    https://loj.ac/problem/10054

    题目描述

      给出(N)个字符串,再给出(M)个字符串,对于(M)个中每一字符串求出(N)个中满足是它的前缀或它是这个前缀的数目的总和。

    思路

      显然,我们需要解决多个字符串前缀的问题,可以选择字典树维护。首先建出(N)个字符串的字典树,不过这里有两种情况,前缀和非前缀,我们要分别维护:

      (①)如果这个字符串是N中某一个字符串的前缀,那么我们就需要维护两个值,一个是某一个节点的经过次数,一个是某一个节点的结束次数,所以如果是字符串的前缀我们最后加上(pass[u]-ed[u]),因为这个节点的(pass)(ed)会重复。

      (②)这个字符串不是(N)中任何一个字符串的前缀,那么只需要在无法找到时返回答案即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int s[10010];
    int ch[500005][3],tot;
    int ed[500005],pass[500005];
    void insert(int len)
    {
        int u=1;
        for(int i=0;i<len;i++)
        {
            int num=s[i];
            if(!ch[u][num])ch[u][num]=++tot;
            u=ch[u][num];
            pass[u]++;
        }
        ed[u]++;
    }
    int find(int len)
    {
        int sum=0,u=1;
        for(int i=0;i<len;i++)
        {
            int num=s[i];
            if(!ch[u][num])return sum;
            u=ch[u][num];
            sum+=ed[u];
        }
        return sum+pass[u]-ed[u];
    }
    int main() 
    {
        int n,m;
        scanf("%d%d",&n,&m);
        tot=1;
        for(int i=1;i<=n;i++)
        {
            int k;
            scanf("%d",&k);
            for(int i=0;i<k;i++)
                scanf("%d",&s[i]);
            insert(k);
        }
        for(int i=1;i<=m;i++)
        {
            int k;
            scanf("%d",&k);
            for(int i=0;i<k;i++)
                scanf("%d",&s[i]);
            printf("%d
    ",find(k));
        }
        return 0;
    }
    
  • 相关阅读:
    对象状态序列化到字节流中
    操作EXCEL完毕后,关闭EXCEL进程
    ORACLE多表查询优化(引)
    再谈需要分析一
    动态添加table,动态添加控件
    ref传参时出错
    SqlServer2000下实现行列转换
    调用结构属性、方法或公共字段的区别
    拆箱存在的隐患
    鼠标悬停图片,滑动显示文字
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11788314.html
Copyright © 2020-2023  润新知