刷题总结——字符串(ssoj)

题目:

给定n个小的字符串T和一个大的字符串S,先输出T总共再S中出现了多少次

然后q个询问···每次修改S上的一个字母,然后再次输出上述答案···

n小于1000,q<200000,T的总长度和S的长度都小于100000;

题解:

我们可以发现,每次修改位置P,那么S影响的范围只有在P-MAX到P+MAX的范围,其中MAX为T的最长长度····所以将这一范围的S跑一边AC自动机··然后更新答案即可··

这道题也让我发现我做AC自动机以来一直有的一个不好的习惯··每次求出现次数都是暴力跳fail指针,这样再这道题里直接T····

其实再我们bfs构建fail指针时,设u的指针为v,我们可以直接tree[u].cnt+=tree[v].cnt,这样每次加的时候直接加上一个节点cnt就可以了··不用暴力跳fail···代码:

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
queue<int>que;
const int N=100005;
struct node
{
  int son[26],cnt,fail;
  void clear()
  {
    memset(son,0,sizeof(son));
    cnt=fail=0;
  }
}tree[N];
int n,m,T,tot,maxx=0;
char s[N],t[5];
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<'0'||c>'9';c=getchar());
  for(;c<='9'&&c>='0';c=getchar())  f=(f<<3)+(f<<1)+c-'0';  
  return 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 ;
}

inline void build()
{
  int po=1;
  int len=strlen(s);maxx=max(maxx,len);
  for(int i=0;i<len;i++)
  {
    if(!tree[po].son[s[i]-'a'])
      tree[tree[po].son[s[i]-'a']=++tot].clear();
    po=tree[po].son[s[i]-'a'];
  }
  tree[po].cnt++;
}
inline void buildfail()
{
  que.push(1);
  while(!que.empty())
  {
    int u=que.front();que.pop();
    for(int i=0;i<26;i++)
    {
      int v=tree[u].fail;
      while(!tree[v].son[i])  v=tree[v].fail;
      v=tree[v].son[i];int w=tree[u].son[i];
      if(w)  tree[w].fail=v,que.push(w),tree[w].cnt+=tree[v].cnt; 
      else tree[u].son[i]=v;
    }
  }
}
int main()
{
  //freopen("string.in","r",stdin);
  //freopen("string.out","w",stdout);
  n=R(),m=R();
  for(int i=0;i<26;i++)
    tree[0].son[i]=1;
  tree[tot=1].clear();
  for(int i=1;i<=n;i++)
  {
    scanf("%s",s);   
    build();
  }
  buildfail();
  scanf("%s",s);
  int len=strlen(s),a;
  int now=1,ans=0;
  for(int i=0;i<len;i++)
  {
    now=tree[now].son[s[i]-'a'];
    ans+=tree[now].cnt;
  }
  W(ans),putchar('\n');
  while(m--)
  {  
      a=R();scanf("%s",t);
    int now=1,ans1=0,ans2=0;
    for(int i=max(0,a-maxx);i<=min(a+maxx-1,len-1);i++)
    {
      now=tree[now].son[s[i]-'a'];                   
      ans1+=tree[now].cnt;
    }
    ans-=ans1;
    s[a-1]=t[0];now=1;
    for(int i=max(0,a-maxx);i<=min(a+maxx-1,len-1);i++)
    {
      now=tree[now].son[s[i]-'a'];
      ans2+=tree[now].cnt;
    }
    ans+=ans2;
    W(ans),putchar('\n');
  }
  return 0;
}

 

转载于:https://www.cnblogs.com/AseanA/p/7677782.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Postman是一款常用的API开发和测试工具,可以用于发送HTTP请求并查看响应结果。在Postman中,可以通过Authorization界面来设置请求的认证方式。 以下是使用Postman的Authorization界面进行认证的步骤: 1. 打开Postman应用程序,并创建一个新的请求。 2. 在请求的URL栏中输入需要发送请求的URL地址。 3. 点击右侧的"Authorization"选项卡,进入认证设置界面。 4. 在认证设置界面中,选择合适的认证类型。根据提供的引用内容,可以选择"OAuth 2.0"认证类型。 5. 在"OAuth 2.0"认证类型下,填写相应的认证参数。根据提供的引用内容,需要填写"Authorization URL"和"Access Token URL"。 - 在"Authorization URL"中,填写引用中提供的URL地址:http://localhost:8090/auth/oauth/authorize?client_id=ssoj-pc&response_type=token - 在"Access Token URL"中,填写引用中提供的URL地址:http://localhost:8080/oauth/token?code=6s9qUj&grant_type=authorization_code&redirect_uri=http://www.mayikt.com/callback&scope=all 6. 根据需要,填写其他相关的认证参数,例如"Client ID"、"Client Secret"等。 7. 点击"Get New Access Token"按钮,开始进行认证流程。 8. 根据认证流程的要求,可能需要输入用户名和密码等信息。 9. 完成认证流程后,会在界面上显示获取到的Access Token信息。 10. 点击"Use Token"按钮,将Access Token添加到请求的Header中。 11. 完成认证设置后,可以点击"Send"按钮发送请求,并查看响应结果。 请注意,以上步骤仅为示例,实际使用时需要根据具体的认证方式和参数进行设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值