[luogu2414 NOI2011]阿狸的打字机 (AC自动机)

本文介绍如何使用AC自动机解决一个特定问题:在一系列输入中寻找预设模式的出现次数。通过构建AC自动机和应用深度优先搜索算法,文章详细解释了如何高效地处理大量字符串匹配任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[luogu2414 NOI2011]阿狸的打字机 (AC自动机)

传送门

Solution

我们知道AC自动机上如果有一点A的fail[A]->B那么B为A的一个后缀

那么我们的问题\((x,y)\)就变为在y中有多少个点直接或间接连向x的终止节点

如果写暴力的话就是遍历y的所有点,对于每个点,我们往上暴跳fail,如果遇到x单词的结尾就ans+1

然而我可以利用dfs序和数据结构优美的完成

首先我们求出fail树(树边与fail相反)的dfs序,并将询问按y排序,然后从头扫读入的字符串,扫的时候给每个点对应的dfs序位置+1。
每当扫完一个字符串时,求出这个字符串作为y的贡献。
具体来说就是找到这个字符串对应的x,对每一个x的终止节点,求出子树的权值和即可

Code

//By Menteur_Hxy
#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define fi first
#define se second
#define Re register 
#define Ms(a,b) memset(a,(b),sizeof(a))
#define Ee(i,u) for(Re int i=head[u];i;i=nxt[i])
#define Fo(i,a,b) for(Re int i=(a),_=(b);i<=_;i++)
#define Ro(i,a,b) for(Re int i=(b),_=(a);i>=_;i--)
#define Add(a,b) nxt[++cnt]=head[a],to[cnt]=b,head[a]=cnt
using namespace std;
typedef pair<int,int> PII;

inline int read() {
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x*f;
}

const int L=1e5+10;
int m,tot,cnt;
int str[L],nxt[L],to[L],head[L],dfn[L],low[L],ans[L];
char ch[L];
vector <PII> As[L];

queue <int> Q;
struct AC_Automation{
    int nd[L][26],fail[L],fa[L],ret;
    AC_Automation() {Ms(nd,0);Ms(fail,0);Ms(fa,0);ret=0;}
    void ins(char *s) {
        int len=strlen(s),now=0,*p;
        Fo(i,0,len-1) {
            if(s[i]=='P') str[++tot]=now;
            else {
                if(s[i]=='B') now=fa[now];
                else {p=&nd[now][s[i]-'a'];if(!*p)*p=++ret;fa[*p]=now;now=*p;}
            }
        } 
    }
    void build() {
        Fo(i,0,25) if(nd[0][i]) fail[nd[0][i]]=0,Q.push(nd[0][i]);
        while(!Q.empty()) {
            int now=Q.front(),*p;Q.pop();
            Fo(i,0,25) if(*(p=&nd[now][i])) fail[*p]=nd[fail[now]][i],Q.push(*p);
                else *p=nd[fail[now]][i];
        }
    }
}AC;

struct BIT{
    int da[L];
    BIT() {clear();}
    void clear() {Ms(da,0);}
    void add(int x,int k) {for(;x<=L;x+=x&-x)da[x]+=k;}
    int qry(int x) {int res=0;for(;x;x-=x&-x)res+=da[x];return res;}
}T;

void dfs(int u) {
    dfn[u]=++tot;
    Ee(i,u) dfs(to[i]);
    low[u]=tot;
}

int main() {
    scanf("%s",ch); AC.ins(ch); AC.build();
    m=read();
    Fo(i,1,m) {
        int x=read(),y=read();
        As[y].push_back(PII(x,i));
    }
    Fo(i,1,AC.ret) Add(AC.fail[i],i); dfs(0);
    T.add(dfn[0],1); int now=0,tmp=0;
    for(Re int i=0;ch[i];i++) {
        if(ch[i]=='P') {
            tmp++;
            Fo(j,0,As[tmp].size()-1) {
                int x=str[As[tmp][j].fi];
                ans[As[tmp][j].se]=T.qry(low[x])-T.qry(dfn[x]-1);
            }
        } else if(ch[i]=='B') T.add(dfn[now],-1),now=AC.fa[now];
        else now=AC.nd[now][ch[i]-'a'],T.add(dfn[now],1);
    }
    Fo(i,1,m) printf("%d\n",ans[i]);
    return 0;
}
posted @ 2018-10-08 12:01 Menteur_Hxy 阅读( ...) 评论( ...) 编辑 收藏
在IT领域,尤其是地理信息系统(GIS)中,坐标转换是一项关键技术。本文将深入探讨百度坐标系、火星坐标系和WGS84坐标系之间的相互转换,并介绍如何使用相关工具进行批量转换。 首先,我们需要了解这三种坐标系的基本概念。WGS84坐标系,即“World Geodetic System 1984”,是一种全球通用的地球坐标系统,广泛应用于GPS定位和地图服务。它以地球椭球模型为基础,以地球质心为原点,是国际航空和航海的主要参考坐标系。百度坐标系(BD-09)是百度地图使用的坐标系。为了保护隐私和安全,百度对WGS84坐标进行了偏移处理,导致其与WGS84坐标存在差异。火星坐标系(GCJ-02)是中国国家测绘局采用的坐标系,同样对WGS84坐标进行了加密处理,以防止未经授权的精确位置获取。 坐标转换的目的是确保不同坐标系下的地理位置数据能够准确对应。在GIS应用中,通常通过特定的算法实现转换,如双线性内插法或四参数转换法。一些“坐标转换小工具”可以批量转换百度坐标、火星坐标与WGS84坐标。这些工具可能包含样本文件(如org_xy_格式参考.csv),用于提供原始坐标数据,其中包含需要转换的经纬度信息。此外,工具通常会附带使用指南(如重要说明用前必读.txt和readme.txt),说明输入数据格式、转换步骤及可能的精度问题等。x86和x64目录则可能包含适用于32位和64位操作系统的软件或库文件。 在使用这些工具时,用户需要注意以下几点:确保输入的坐标数据准确无误,包括经纬度顺序和浮点数精度;按照工具要求正确组织数据,遵循读写规则;注意转换精度,不同的转换方法可能会产生微小误差;在批量转换时,检查每个坐标是否成功转换,避免个别错误数据影响整体结果。 坐标转换是GIS领域的基础操作,对于地图服务、导航系统和地理数据分析等至关重要。理解不同坐标系的特点和转换方法,有助于我们更好地处
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值