ACM 字符串匹配 学习

1.常见的匹配一个个匹配
2.高级一点的用KMP匹配
3.做到一道题 KMP超时 数据量挺大的
Given a string s, process q queries, each having one of the following forms:
1 i c — Change the ith character in the string to c.
2 l r y — Consider the substring of s starting at position l and ending at position r. Output the number of times y occurs as a substring in it.

Input
The first line contains an integer T (1 ≤ T ≤ 5), representing the case number.
For each case, the first line of the input contains the string s (1 ≤ |s| ≤ 10^5) of lowercase English letters.
The second line contains an integer q (1 ≤ q ≤ 10^5) — the number of queries to process.
The next q lines describe the queries and may have one of the following forms:
1 i c (1 ≤ i ≤ |s|)
2 l r y (1 ≤ l ≤ r ≤ |s|)
c is a lowercase English letter and y is a non-empty string consisting of only lowercase English letters.
The sum of |y| over all queries of second type is at most 3*10^5.
It is guaranteed that there is at least one query of second type.
All strings are 1-indexed.|s| is the length of the string s.
Output
For each query of type 2, output the required answer in a separate line.
举个栗子 还是不太会解释 能看懂就看看不懂只能自己推 要是有好的解释方法欢迎留言
这里写图片描述

abccabc 
bitset 是从后面往前存的 数据做了处理,下标为1
a:      ……000100010    倒着读 第1a5a
b:       ……001000100   倒着读 第2位b 第6位b
c:       ……0010011000   倒着读 第3,4,7位c 
可以表示原字符串每个字母出现的位置
具体我在代码中解释
#include <bits/stdc++.h>
using namespace std;
const int maxn=100010;
bitset<maxn>s[27],ans;
char a[maxn],b[maxn],c[3];
int main()
{
    int T;
    cin>>T;
    while(T--){
        for(int i=0;i<27;i++){
            s[i].reset();
        }//清零
        scanf("%s",a+1);//读取,从第一个开始
        T=strlen(a+1); //计算长度
        int i,j,l,r,Q,opt;
        for(i=1;i<=T;i++)  //开26个bitset 保存每个字母出现的位置
            s[a[i]-'a'].set(i);
        cin>>Q;  
        while(Q--){
            cin>>opt;
            if(opt==1){
                scanf("%d%s",&j,c);
                s[a[j]-'a'][j]=0;  //当前字母的j位清零
                s[(a[j]=c[0])-'a'][j]=1; //读入字母的j位变1
            }
            else {
                cin>>l>>r;  
                scanf("%s",b);
                int S=strlen(b);
                if(S>r-l+1) { //长度大于区间打印0,continue
                    puts("0"); 
                    continue;
                }
                ans.set();   //全部置1
                for(i=0;i<S;i++){
                    // printf("%d %d\n",(s[b[i]-'a']>>i).to_ulong(),i);
                    ans&=(s[b[i]-'a']>>i);
                    // printf("ans=%d\n",ans.to_ulong() );
                }
                // printf("%d\n", (ans>>l).count());
                // printf("%d\n", (ans>>(r-S+2)).count());
                printf("%d\n",(ans>>l).count()-(ans>>(r-S+2)).count());
                //感觉这一个不算好理解,看看我例子中的abccabc
                //l=1   r=7  s=3  b="abc"
                //最后得到的结果……00100010

                //每个1都表示当前开始可以匹配到abc

            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38677814/article/details/80181116
今日推荐