NOIP模拟 string【AC自动机】

题目大意:

给定n个匹配串T,(|T|<=100),再给1个串S(|S|<=100000),问所有T共在S中出现了多少次。
再给m次操作pos,c,每次把S位置为pos的字母改为c(下标从一开始),每次操作后,问所有T共在S中出现了多少次。
n<=1000,m<=200000;

解题思路:

由于每个匹配串比较短,所以修改pos位置只会在[pos-|T|,pos+|T|]这个范围内的匹配改变,所以每次只用把这段区间放到AC自动机上去跑,减去这段区间的原贡献,加上改后的新贡献即可。

注意统计时不用一直跳fail指针,只用在建立fail的时候加上其所有fail链上的值即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

int getint() 
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')c=getchar(),f=-1;
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

int buf[1024];
inline void W(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x) buf[++buf[0]]=x%10,x/=10;
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}

const int N=1005;
const int M=1e5+5;
const int L=105;
struct node
{
    int cnt,fail,son[26];
}tr[N*L];
char s[M];
int tot,n,m,mx;

void insert()
{
    int len=strlen(s),po=1;
    mx=max(mx,len);
    for(int i=0;i<len;i++)
    {
        if(!tr[po].son[s[i]-'a'])
            tr[po].son[s[i]-'a']=++tot;
        po=tr[po].son[s[i]-'a'];
    }
    tr[po].cnt++;
}

void buildfail()
{
    int head=0,tail=1;
    static int que[N*L];
    que[tail]=1;
    while(head<tail)
    {
        head++;
        int u=que[head],v,w;
        for(int i=0;i<26;i++)
        {
            v=tr[u].fail;
            while(!tr[v].son[i])v=tr[v].fail;
            v=tr[v].son[i],w=tr[u].son[i];
            if(w)tr[w].fail=v,que[++tail]=w,tr[w].cnt+=tr[v].cnt;
            else tr[u].son[i]=v;
        }
    }
}

int ac_auto(int l,int r)
{
    int po=1,ans=0,tmp;
    for(int i=l;i<=r;i++)
    {
        po=tr[po].son[s[i]-'a'];
        ans+=tr[po].cnt;
    }
    return ans;
}

int main()
{
    //freopen("string.in","r",stdin);
    //freopen("string.out","w",stdout);
    int pos;char c;
    tot=1;
    for(int i=0;i<26;i++)tr[0].son[i]=1;
    n=getint(),m=getint();
    while(n--)
        scanf("%s",s),insert();
    buildfail();
    scanf("%s",s);
    int len=strlen(s);
    int ans=ac_auto(0,len-1);
    W(ans),putchar('\n');
    while(m--)
    {
        pos=getint();
        pos--;
        for(c=getchar();c<'a'||c>'z';c=getchar());
        int l=max(0,pos-mx),r=min(len-1,pos+mx);
        ans-=ac_auto(l,r);
        s[pos]=c;
        ans+=ac_auto(l,r);
        W(ans),putchar('\n');
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值