[NOI2011]阿狸的打字机【AC自动机fail树+树状数组】

2023-10-27

题目链接 P2414


  题目给出N个字符串,我们现在想知道的是第x个字符串在第y个字符串中出现的次数是多少次?

  求每个字符在其余字符中出现次数,想到从AC自动机上走,其实可以看作是求它的后缀的前缀中有多少个是满足的,换言之,我们可以去fail树中的父亲结点中查询。

就譬如说对于aa和aabaa两个字符串,我们搭建字典树

  并且对应上fail指针,我们可以知道,aa出现的次数为两次,分别是以整个串aabaa构成的前缀,以及以aa(aabaa的后缀)构成的前缀。

  搭建对应的fail树,我们知道每个对应的权值只能是以它的子树上的贡献,所以我们求它的子树中的某个节点的贡献,一定是它对应子树(含自己),所产生的贡献。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, len, M, tot, rid[maxN];
char s[maxN];
struct node
{
    int nex[26], val, fail, fa;
    inline void clear() { memset(nex, 0, sizeof(nex)); val = fail = fa = 0; }
}a[maxN];
inline void Insert()
{
    int root = 0;
    for(int i=0, ch; i<len; i++)
    {
        if(s[i] == 'P')
        {
            rid[++N] = root;
            continue;
        }
        if(s[i] == 'B')
        {
            root = a[root].fa;
            continue;
        }
        ch = s[i] - 'a';
        if(!a[root].nex[ch])
        {
            ++tot;
            a[tot].clear();
            a[tot].fa = root;
            a[root].nex[ch] = tot;
        }
        root = a[root].nex[ch];
    }
}
int head[maxN], cnt;
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
inline void build_fail()
{
    queue<int> Q; Q.push(0);
    int tmp, son, p;
    while(!Q.empty())
    {
        tmp = Q.front(); Q.pop();
        for(int i=0; i<26; i++)
        {
            son = a[tmp].nex[i];
            if(son)
            {
                if(!tmp) a[son].fail = 0;
                else
                {
                    p = a[tmp].fail;
                    while(p && !a[p].nex[i]) p = a[p].fail;
                    a[son].fail = a[p].nex[i];
                }
                Q.push(son);
                addEddge(a[son].fail, son);
            }
            else a[tmp].nex[i] = a[a[tmp].fail].nex[i];
        }
    }
}
int trie[maxN] = {0};
inline void update(int x, int val) { while(x < maxN) { trie[x] += val; x += lowbit(x); } }
inline int query(int x) { int ss = 0; while(x) { ss += trie[x]; x -= lowbit(x); } return ss; }
inline int Range_Query(int x, int y) { return query(y) - query(x - 1); }
int dfn[maxN] = {0}, _Index, siz[maxN];
void dfs(int u)
{
    dfn[u] = ++_Index; siz[dfn[u]] = 1;
    for(int i=head[u], v; ~i; i=edge[i].nex) { v = edge[i].to; dfs(v); siz[dfn[u]] += siz[dfn[v]]; }
}
struct Question
{
    int x, y, id;
    Question(int a=0, int b=0, int c=0):x(a), y(b), id(c) {}
    friend bool operator < (Question e1, Question e2) { return e1.y < e2.y; }
}q[maxN];
int now_ques_ID, ans[maxN];
void dfs_Trie()
{
    int root = 0, id_N = 0;
    for(int i=0, ch; i<len; i++)
    {
        if(s[i] == 'P')
        {
            id_N++;
            while(q[now_ques_ID].y == id_N)
            {
                int x = rid[q[now_ques_ID].x];
                ans[q[now_ques_ID].id] = Range_Query(dfn[x], dfn[x] + siz[dfn[x]] - 1);
                now_ques_ID++;
            }
            continue;
        }
        if(s[i] == 'B')
        {
            update(dfn[root], -1);
            root = a[root].fa;
            continue;
        }
        ch = s[i] - 'a';
        root = a[root].nex[ch];
        update(dfn[root], 1);
    }
}
inline void init()
{
    N = tot = cnt = _Index = 0;
    now_ques_ID = 1;
    a[0].clear();
    memset(head, -1, sizeof(head));
}
int main()
{
    scanf("%s", s); len = (int)strlen(s);
    init();
    Insert();
    build_fail();
    dfs(0);
    scanf("%d", &M); int x, y;
    for(int i=1; i<=M; i++)
    {
        scanf("%d%d", &x, &y);
        q[i] = Question(x, y, i);
    }
    sort(q + 1, q + M + 1);
    dfs_Trie();
    for(int i=1; i<=M; i++) printf("%d\n", ans[i]);
    return 0;
}
/*
aaPbaaP
1
1 2
ans:2
*/

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[NOI2011]阿狸的打字机【AC自动机fail树+树状数组】 的相关文章

  • 日志聚合工具loki

    目录 1 loki是什么 2 loki特点 3 loki组成 4 loki安装 4 1 添加helm的chart库 4 2 安装loki及promtail 4 3 安装grafana 5 配置和使用 6 日志选择和过滤 6 1 日志选择器
  • ROS Melodic 安装时所遇到的问题及解决方法

    文章目录 参考教程 所遇到的问题 1 sudo rosdep init 2 ERROR default sources list file already exists etc ros rosdep sources list d 20 de
  • 接口入参格式为x-www-form-urlencoded 的处理

    一般情况下接口入参数格式要求是JSON通用格式 但有些时候接口入参数要求是x www form urlencoded格式 这种格式前端就不能传递JSON格式数据了 如果传递JSON数据的话 接口会报异常 下面对此种情况做解释处理 1 接口入
  • Elasticsearch 配置内存量

    场景 由于配置es之后服务器内存负载过高 原因 初步原因是es内存暂用过高 处理 修改es的配置文件jvm options 根据服务器情况一般是配置服务器内存的一半
  • 手残,双硬盘(SSD+HDD)双系统(Win10+ubuntu)用easyBCD删除win10引导项怎么办?戳这里

    问题描述 博主处女座 电脑双硬盘 固态 机械 因为学习需要 装了双系统 Win10 Ubuntu 这个也是费了不少功夫才成功 不知道怎么装的可以看我这个http blog csdn net x1825048925 article detai
  • 怎样的架构设计才是真正的数据仓库架构

    在各个网站和论坛 一说到数据仓库 基本都想到了 ETL DW OLAP 一说到数据仓库设计 就是按照行业规范和客户需求调研 设计主题 然后设计对应的 事实表 维表 但是 这就是真正的数据仓库总体设计么 关于上面说的主题设计 以及前端展现 这
  • cfssljson详解1

    一 cfssljson简介 大多数cfssl命令的输出内容都是JSON格式的 而cfssljson工具可以将这些JSON格式的输出内容作为输入内容 并按照key键 key certificate CSR and bundle 将之区分然后输
  • 机器学习-决策树算法ID3实现,含例子(红酒分类)

    决策树原理实现代码如下所示 参考自机器学习实践 Peter Harrington import math x 0 1 no 0 1 no 1 0 no 1 1 yes 1 1 no 1 1 no 1 1 maybe 1 1 maybe 1
  • 手把手教你搭建SpringCloudAlibaba项目

    SpringCloud Alibaba全集文章目录 零 手把手教你搭建SpringCloudAlibaba项目 一 手把手教你搭建SpringCloud Alibaba之生产者与消费者 二 手把手教你搭建SpringCloudAlibaba
  • 数据结构——AOE与算法——关键路径的计算

    AOE图 节点表示事件 弧表示活动 弧的权重表示活动进行的时间 关键路径 在AOE网中 从起始点到终点具有最大路径长度的一条路径被称为关键路径 算法思路 1 利用拓扑排序求出AOE网的一个拓扑序列 2 从拓扑排序的序列的第一个顶点 源点 开
  • 设计模式的 C++ 实现---策略模式

    前文回顾 单例模式 一 单例模式 二 观察者模式 简单工厂模式 工厂方法模式 一 工厂方法模式 二 抽象工厂模式 一 抽象工厂模式 二 原型模式 外观模式 中介者模式 代理模式 装饰者模式 前言 所谓策略即解决一件事情的算法 或者方法 是一

随机推荐

  • intel至强服务器芯片制程,64核自研芯片性能提升7倍,追平英特尔至强

    不久之前 英特尔发布了至强铂金8284处理器 单个内核拥有高达28核心56线程 刷新了业界顶尖水平 事实上 在服务器级处理器中 英特尔的产品一向具有重要的地位 它的服务器芯片不仅技术先进 而且耐用程度优质 能耗控制良好 可以说是服务器必备产
  • AJAX请求返回流 下载Excel文件

    AJAX请求返回流 下载Excel文件 模拟请求 var xhr new XMLHttpRequest 文件名称 var fileName 1 xls xhr open POST http 127 0 0 1 8001 Api Downlo
  • 并发编程篇

    并发编程篇 线程基础 线程和进程的区别 面试官 说一下线程和进程的区别 候选人 嗯 好 进程是正在运行程序的实例 进程中包含了线程 每个线程执行不同的任务 不同的进程使用不同的内存空间 在当前进程下的所有线程可以共享内存空间 线程更轻量 线
  • docker部署常用服务器(redis,nginx,mysql,tomcat)

    docker部署服务器 docker部署redis docker部署nginx docker部署mysql docker部署tomcat docker部署redis 参考这篇博客 写的很详细 docker部署nginx 1 搜索镜像 doc
  • opencv imread()默认加载三通道图像

    今天用python opencv 函数 cv2 imread加载图像 图像是单通道的但是加载完之后就变成三通到了 处理了半天的bug才发现是这里出现了问题 介绍一下imread函数 c 函数模型 include
  • 使用@JsonInclude来实现字段为Null不传递,不为null才传递

    屁话不多说 直接上需求 code 0 msg 成功 data orderId 161873371171128075 buyerName 张三 buyerPhone 18868877111 buyerAddress 总部 buyerOpeni
  • 实战分享:基于python PyQt5的视频监控系统 完整代码数据 课程设计

    代码视频讲解 PyQt5的视频监控系统 基于python PyQt5的视频监控系统 完整代码可直接运行 哔哩哔哩 bilibili import sys import cv2 from PyQt5 Qt import from PyQt5
  • pandoc 使用_如何使用Pandoc撰写研究论文

    pandoc 使用 本文深入探讨了如何使用 主要是 Markdown语法来撰写研究论文 我们将介绍如何创建和引用节 图形 在Markdown和LaTeX中 和参考书目 我们还将讨论麻烦的案例 以及为什么在LaTeX中编写它们是正确的方法 研
  • CGAL配置的一点心得(各种错误的解决办法)

    这几天由于项目关系 花了些时间配置了一下CGAL 说实话走了不少弯路 谈谈我的心得吧 具体流程我不想讲 这种东西网上博客一搜一大把 而且都有一定的参考价值 当然最值得推荐的还是官网http www cgal org download win
  • 新能源汽车涨价的背后,究竟有哪些原因?

    新能源车企宣布涨价 前段时间 不仅油价接连上涨 新能源车企也接连宣布调价 根据不完全统计 今年2月后 已有超过16家车企因原料价格上涨宣布提价 下面云恒制造小编带大家来看一下 主要新能源车企涨价情况 其余车企如岚图 极氪等内部正在酝酿涨价
  • dbnull mysql_关于.net:无法将’System.DBNull’类型的对象强制转换为’System.String’类型...

    本问题已经有最佳答案 请猛点这里访问 我正在使用MVC3 ASP 并已将我的web config文件配置为以root用户身份登录MYSQL数据库 我创建了许多存储过程 我可以很好地连接 我现在想要将此登录用户更改为公共用户 称为tempus
  • g.729a 音频编解码算法

    g 729 spirit dsp定义 音频压缩编码 1 什么是语音编码技术 其发展与现状是怎样的 答 语音信号的数字化传输 一直是通信的发展方向之一 采用低速率语音编码技术进行语音传输比语音信号模拟传输有诸多优点 现代通信的发展趋势决定了语
  • 深入理解Https如何保证通信安全

    作为一名ABC搬运工 我相信很多人都知道Https 也都知道它是用来保证通信安全的 但是如果你没有深入了解过Https 可能并不知道它是如何保证通信安全的 我也是借着这次机会 和大家分享下我深入了解的一个过程 本文主要带着以下几个问题进行探
  • Ubuntu18.04更换源及类似问题解决方案

    Ubuntu18 04更换源及类似问题解决方案 文章目录 Ubuntu18 04更换源及类似问题解决方案 1 前言 2 Ubuntu18 04 LTS 更换国内源 3 最后 1 前言 目前部分开发板使用的Ubuntu操作系统 使用Qt RO
  • WSL重启方法

    WSL Ubuntu18 04 LTS 重启方法 以管理员权限运行cmd gt gt net stop LxssManager 停止 gt gt net start LxssManager 启动
  • 抓取一闪而过的提示消息文本

    前端业务操作出现一闪而过的message提示信息 它们有一个特点就是显示1 2s后会自动消失 例如下图1 图1 这些消息不像 alert 警告框 confirm 确认框 和prompt 提示框 那样 需要用户手动点击确定或取消按钮后才消失
  • 华为od机考真题-HJ32密码截取(中等)

    求最大回文子串 while 1 try str1 input if len str1 1 print 1
  • 渗透测试学习目录

    网络攻击防范 课程介绍 1 HTML 01 HTML标签和文本属性 02 form表单 input 标签 属性 03 a标签 img标签 table标签 04 无序列表和有序列表 05 frameset frame 框架的使用 2 div
  • VS离线安装NuGet包

    VS离线安装NuGet包 以VS 2017为例 一 下载NuGet包 官方NuGet包下载网址 https www nuget org 1 搜索需要下载的包名称 点击进入包详情页面 2 点击Download package 下载离线包 3
  • [NOI2011]阿狸的打字机【AC自动机fail树+树状数组】

    题目链接 P2414 题目给出N个字符串 我们现在想知道的是第x个字符串在第y个字符串中出现的次数是多少次 求每个字符在其余字符中出现次数 想到从AC自动机上走 其实可以看作是求它的后缀的前缀中有多少个是满足的 换言之 我们可以去fail树