• CodeForces 710F 强制在线AC自动机


    题目链接:http://codeforces.com/contest/710/problem/F

    题意:维护一个集合,集合要求满足三种操作。 1 str:向集合插入字符串str(保证不会插入之前已经插入过的字符串) 2str:从集合中删除字符串str(保证删除的str一定在集合中) 3 str:str的子串有多少个在集合中出现过。

    思路:题目意思就是一个可以插入/删除/查询的AC自动机。但是如果我们暴力求解,每次添加/删除一个字符串到自动机中求从前求一边适配指针的话会TLE。所以我们考虑用其他方法,设置一个恰当的阈值。如果小于这个阈值则把字符串放入trie树中,而大于阈值的直接保存下来。然后对于添加标记+1 ,删除标记-1。关于操作3把字符串分别与字典树的串匹配和保存下来的串匹配。关于在字典树的匹配。我们只需枚举str的所有后缀去匹配字典树即可。对于保存下来的串我们对其每一个建立KMP的next数组,然后就是普通的KMP的单模式匹配了。     用时不到1S

    #define _CRT_SECURE_NO_DEPRECATE
    #include<stdio.h>  
    #include<string.h>  
    #include<cstring>
    #include<algorithm>  
    #include<queue>  
    #include<math.h>  
    #include<time.h>
    #include<vector>
    #include<iostream>
    using namespace std;
    typedef long long int LL;
    const int MAXN = 300000 + 10;
    const int CASE_SIZE = 26;
    const int S_SIZE = 1000;
    const int B_SIZE = MAXN / S_SIZE + 10;
    struct Trie{
        int child[MAXN][CASE_SIZE], value[MAXN],trieN,root;
        void init(){
            trieN = root = 0; value[root] = 0;
            memset(child[root], -1, sizeof(child[root]));
        }
        int newnode(){
            trieN++; value[trieN] = 0;
            memset(child[trieN], -1, sizeof(child[trieN]));
            return trieN;
        }
        void insert(char *s,int val){
            int x = root;
            for (int i = 0; s[i]; i++){
                int d = s[i] - 'a';
                if (child[x][d] == -1){
                    child[x][d] = newnode();
                }
                x = child[x][d];
            }
            value[x] += val;
        }
        int search(char *s){
            int sum = 0, x = root;
            for (int i = 0; s[i]; i++){
                int d = s[i] - 'a';
                if (child[x][d] == -1){
                    break;
                }
                x = child[x][d];
                sum += value[x];
            }
            return sum;
        }
    }trie;
    struct KMP{
        int Next[MAXN];
        void getNext(string s,int len){
            memset(Next, 0, sizeof(Next));
            int i = 0, j = -1; Next[0] = -1;
            while (i < len){
                if (j == -1 || s[i] == s[j]){
                    ++i; ++j;
                    Next[i] = j;
                }
                else{
                    j = Next[j];
                }
            }
        }
        int search(string s,char *str){
            int sum = 0, j = 0, lens = s.length(),lenstr=strlen(str);
            getNext(s, s.length());
            for (int i = 0; i < lenstr; i++){
                while (j>0 && s[j] != str[i]){
                    j = Next[j];
                }
                if (s[j] == str[i]){
                    j++;
                }
                if (j == lens){
                    sum++; j = Next[j];
                }
            }
            return sum;
        }
    }kmp;
    string Bstr[B_SIZE];
    char str[MAXN];
    int cnt, Bvalue[B_SIZE];
    int main() {
        int t, m,len,val;
        while (~scanf("%d", &m)) {
            trie.init(); cnt = 0; memset(Bvalue, 0, sizeof(Bvalue));
            for (int i = 1; i <= m; i++){
                scanf("%d%s", &t, str);
                len = strlen(str);
                if (t == 1 || t == 2){ //插入和删除
                    val = (t == 1 ? 1 : -1); //插入=1,删除=-1
                    if (len <= S_SIZE){//小与阈值删除字典树
                        trie.insert(str, val);
                    }
                    else{ //大于阈值直接保存起来
                        Bstr[cnt] = string(str);
                        Bvalue[cnt++] = val; //标记是添加的还是删除的
                    }
                }
                else{ //查询
                    LL ans = 0;
                    for (int i = 0; i < len; i++){ //字典树上匹配
                        ans += trie.search(str + i);
                    }
                    for (int i = 0; i < cnt; i++){ //暴力KMP匹配
                        if (Bstr[i].length() > len){ continue; }
                        ans += kmp.search(Bstr[i], str)*Bvalue[i];
                    }
                    printf("%I64d
    ", ans);
                    fflush(stdout);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    客户端用java api 远程操作HDFS以及远程提交MR任务(源码和异常处理)
    HighCharts终极版本
    Highcharts网页版
    情感化设计中的手绘应用表现
    前端批量下载文件
    PHP 大文件下载,文件传输,支持断点续传。 2g以上超大文件也有效
    PHP超大文件下载,断点续传下载
    php下载大文件,支持断点续传案例
    解决PHP超大文件下载,断点续传下载的方法详解
    PHP如何异步断点续传大文件
  • 原文地址:https://www.cnblogs.com/kirito520/p/5838016.html
Copyright © 2020-2023  润新知