You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.8 KiB

Eye of the Storm

题目描述

云浅来到了风暴的中心。这里漂浮着一个长为 n 的,由小写字母组成的字符串 S字符串的下标从 1 开始。

想要逃出风暴,就需要回答一些询问。

每次询问会给出一对正整数 l,r 和一个字符串 T,云浅需要回答 S_{l\cdots r} 这段子串内有多少个子序列是 T这里保证 T 的长度为 2

形式化地,你需要求出有多少对 (i,j) 满足 l\le i<j\le r,使得 S_i=T_1,S_j=T_2

现在云浅预测出了风暴在接下来 q 个时刻内的询问,你需要帮她求出每个询问的答案。

输入格式

第一行两个正整数 n,q

第二行一个长为 n 的字符串 S

接下来 q 行,每行会给出两个正整数 l,r 和一个字符串 T,表示云浅需要回答的询问。保证 |T|=2

输出格式

对于每次询问,输出一行一个正整数表示答案。

数据范围

对于 100\% 的数据,1\le n,q\le 2\times 10^5,1\le l\le r\le n,S,T 中只含小写英文字母,|T|=2

测试点编号 n q 其他
1\sim 4 \le 100 \le 100
5\sim 8 \le 5000 \le 5000
9\sim 10 \le 10^5 \le 10^5 所有的 S_i 均相同
11\sim 12 \le 10^5 \le 3
13\sim 16 \le 10^5 \le 10^5
17\sim 20 \le 2\times 10^5 \le 2\times 10^5

题解

记字符集大小为 V=26

考虑设 \text{Sum}(i,c)S_{1\cdots i} 中字符 c 的出现次数,那么答案就是\displaystyle \sum_{l\le i\le r,S_i==T_2}\text{Sum}(i-1,T_1)-\text{Sum}(l-1,T_1) 用一个 vector 来存一下 S 中等于 T_2 的数的出现位置,顺便附带记录一下 \text{Sum},每次查询的时候二分出 r 前面和 l 后面的第一个满足等于 S_i==T_2i 的位置,那么要求的就是 vector 内的一个前缀和。具体可以看代码。

时间复杂度 O(nV+q\log n),空间复杂度 O(nV)

参考代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    for (; (c < '0' || c > '9'); c = getchar()) {
        if (c == '-') {
            f = -1;
        }
    }
    for (; (c >= '0'&& c <= '9'); c = getchar()) {
        x = x * 10 + (c& 15);
    }
    return x * f;
}
int n, q;
string S, T;
#define mk make_pair
#define fi first
#define se second
const int MN = 2e5 + 5;
vector<int > pos[26], sum[26][26];
int f[MN][26];
signed main(void) {
    freopen("ridge.in", "r", stdin);
    freopen("ridge.out", "w", stdout);
    cin >> n >> q;
    cin >> S;
    for (int i = 1; i <= n; i++) {
        int t = (int)(S[i - 1] - 'a');
        for (int x = 0; x < 26; x++) {
            f[i][x] = f[i - 1][x], sum[t][x].push_back(f[i][x]);
        }
        pos[t].push_back(i);
        f[i][t]++;
    }
    for (int t = 0; t < 26; t++) {
        for (int x = 0; x < 26; x++) {
            for (int j = 1; j < sum[t][x].size(); j++) {
                sum[t][x][j] += sum[t][x][j - 1];
            }
        }
    }
    while (q--) {
        int l, r;
        cin >> l >> r >> T;
        if (l > r) {
            puts("**");
            return 0;
        }
        int a = T[0] - 'a', b = T[1] - 'a';
        int ql = lower_bound(pos[b].begin(), pos[b].end(), l) - pos[b].begin();
        int qr = upper_bound(pos[b].begin(), pos[b].end(), r) - pos[b].begin() - 1;
        if (ql > qr) {
            puts("0");
            continue;
        }
        int cnt = qr - ql + 1;
        cout << sum[b][a][qr] - (ql == 0 ? 0 : sum[b][a][ql - 1]) - f[l - 1][a] * cnt << endl;
    }
    return 0;
}