题目传送门

  传送点I

  传送点II

  传送点III

题目大意

   给定一个字母串,要求支持以下操作:

  1. 修改一个位置的字母
  2. 查询一段区间中,字符串$s$作为子串出现的次数

Solution 1 Bitset

  每次匹配一段,可以看成,依次考虑每个位置,匹配的位置对应的起点取交集。例如:

Codeforces 917F Substrings in a String - 后缀自动机 - 分块 - bitset - KMP

  大概就这个意思。

  bitset的count似乎很慢,可以用__builtin_popcount来数中间的位数,然后暴力数两端的位数会快很多。感觉手写倍增法数位数最快。但有人说前面那个内联函数比手写的$O(\log \log n)$的速度要快。

Code

 1 /**
 2  * Codeforces
 3  * Problem#914F
 4  * Accepted
 5  * Time: 2760ms
 6  * Memory: 4300k 
 7  */
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 typedef bool boolean;
11 
12 const int N = 1e5 + 5, alpha = 26;
13 
14 int n, m;
15 char str[N], buf[N];
16 bitset<N> ch[alpha], ans;
17 
18 inline void init() {
19     scanf("%s", str + 1);
20     n = strlen(str + 1);
21     for (int i = 1; i <= n; i++)
22         ch[str[i] - 'a'][i] = 1;
23     scanf("%d", &m);
24 }
25 
26 inline void solve() {
27     int opt, x, y, len;
28     while (m--) {
29         scanf("%d%d", &opt, &x);
30         if (opt == 1) {
31             scanf("%s", buf);
32             ch[str[x] - 'a'][x] = 0, ch[buf[0] - 'a'][x] = 1;
33             str[x] = buf[0];
34         } else {
35             scanf("%d%s", &y, buf + 1);
36             len = strlen(buf + 1);
37             if (y - x + 1 < len) {
38                 puts("0");
39                 continue;
40             }
41             ans.set();
42             for (int i = 1; i <= len; i++)
43                 ans &= (ch[buf[i] - 'a'] >> (i - 1));
44 //            for (int i = 1; i <= n; i++)
45 //                cerr << ans[i] << " ";
46 //            cerr << endl;
47 //            for (int i = 1; i <= n; i++)
48 //                cerr << (ans >> (x - 1))[i];
49 //            cerr << endl;
50             int res = (ans >> x).count() - (ans >> (y - len + 2)).count();
51             printf("%d\n", res);
52         }
53     }
54 }
55 
56 int    main() {
57     init();
58     solve();
59     return 0;
60 }
bitset

相关文章: