• Luogu P3879 【[TJOI2010]阅读理解】


    前言:

    这个题一直有个疑问,最多一千行,每行五千字$1000 imes5000=5e6$

    $5e6 imes26 imes4div1024div1024approx496Mb>125Mb$

    尽管清楚实际空间需求不能到达$5e6$,如何计算直接对文章建$Trie$事实上所需的最大空间呢,本人对此并不清楚,也希望有大佬能为我解决一下这个问题(至于开$5e6 imes26$通过的大佬,我想我这种凡人还达不到这个境界)

    那么,就请我们权且认为直接对文章建$Trie$在空间上是不被允许的,至少是不够保险的

    正文:

    于是提供一种同样是基于$Trie$的方法——对询问建$Trie$

    $10000 imes20 imes26 imes4div1024div1024approx20Mb$

    占空间最多的$Trie$解决了,空间问题就不必担心了

    下面我们考虑对询问建$Trie$下这个问题的解决

    (这不是$Trie$的板子题吗,有什么可考虑的)

    好吧,代码实现细节及一些注意事项,见代码了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int maxn=5e6,maxq=2e5+10;
    int cnt,a[maxq][26],n,m;
    vector<string>v[1010];
    vector<int>ans[10010],val[maxq];
    string tmp;
    int idx(char c)
    {
        return c-'a';
    }
    void insert(int x)
    {
        cin>>tmp;
        int len=tmp.length(),now=0;
        for(int i=0;i<len;i++)
        {
            int c=idx(tmp[i]);
            now=a[now][c]?a[now][c]:a[now][c]=++cnt;
        }
        val[now].push_back(x);
        /*因为可能有相同的查询,这里的简单地用一个
        整形标记就不太合适了,我选择了用vector记录
        这个节点作为所有询问的标记*/
    }
    void check(int x,int y)
    {
        int len=v[x][y].length(),now=0;
        for(int i=0;i<len;i++)
        {
            int c=idx(v[x][y][i]);
            if(!a[now][c])
                return;
                //这个单词一定没有被查询过,直接退回
            now=a[now][c];
        }
        for(int i=0;i<val[now].size();i++)
            ans[val[now][i]].push_back(x);
            //同理在所有询问中保存这个单词曾经出现的文章
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1,num;i<=n;i++)
        {
            scanf("%d",&num);
            for(int j=1;j<=num;j++)
            {
                cin>>tmp;
                v[i].push_back(tmp);
                //采用了vector来存储原文
            }
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            insert(i);
        for(int i=1;i<=n;i++)
            for(int j=0;j<v[i].size();j++)
                check(i,j);
        for(int i=1;i<=m;i++)
        {
            vector<int>::iterator pos=unique(ans[i].begin(),ans[i].end());
            for(vector<int>::iterator it=ans[i].begin();it!=pos;it++)
                printf("%d ",*it);
            printf("
    ");
        }
        /*这里的输出,因为一篇文章里可能多次出现同一单词,
        记得去重,一开始我用的unique,再输出vector中的
        所有元素。但是unique去重时其实并没有删除这些元素
        在这里也被坑了,所以改用迭代器*/
        return 0;
    }



  • 相关阅读:
    C++输入输出缓冲区的刷新问题
    C++11中新特性之:initializer_list详解
    GCC --verbose选项, -lpthread 和-pthread的区别
    C语言的可变参数
    YCM的安装与配置
    【机器学习】正则化的线性回归 —— 岭回归与Lasso回归
    一文读懂线性回归、岭回归和Lasso回归
    美团酒旅数据治理实践
    kettle完成一个数据库到另一个数据的整体迁移
    kettle完成一个数据库到另一个数据的整体迁移
  • 原文地址:https://www.cnblogs.com/ivanovcraft/p/11342215.html
Copyright © 2020-2023  润新知