[NOIP模拟] 字符串

来源:互联网 发布:找出两列中不同的数据 编辑:程序博客网 时间:2024/06/01 09:25

题目大意:

    给出 n 个串(len <= 100), 再给出一个主串(len <= 100000), 给出 Q 次询问, 每次包括一个整数和一个字母,求主串在该整数位置将字母改为该字母后,n个串再主串中出现的次数。

输入简述 :

    输入N <= 1000, Q <= 200000, N 个串,一个主串, Q次询问的整数和字母。

输出简述 :

    最初值 + Q次询问的答案。

sample input :

3 5
ab
bc
abc
acbcb
2 b
3 c
4 a
1 b
3 a

sample ouput :

1
2
3
4
2
1


题解 :

    提说这是 NOI 测试的签到题, 看来还是我太弱了。
    我们考虑每次修改对答案的影响, 每次修改我们只会影响 pos - len + 1 到 pos + len - 1 的值, len 为非主串的字符串长度, pos为修改的位置, 于是我们只需要求出在这段区间的值就可以了, 那我们这里就会跑两边 AC 自动机,由于 len 不超过 100, 但我们会多次跳 fail, 所以这里可能会超, 于是我们考虑优化,我们将每个 AC 自动机上的点, 把他们所有的 fail 指针所跳的点的 cnt 都加起来,在预处理完成,这样我们就不用跳 fail 了。




代码 :

#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <cmath>#include <ctime>#include <map>#include <vector>#include <queue>#define clr(a) memset(a, 0, sizeof(a))using namespace std;inline int read() {    int i = 0, f = 1;    char ch = getchar();    while(!isdigit(ch)) {        if(ch == '-') f = -1; ch = getchar();    }    while(isdigit(ch)) {        i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();    }    return i * f;}const int MAXN = 1e5 + 5;int mx;char s[MAXN];struct AC {    int tot;    struct point {        int trans[26], cnt, fail;        void clear() {            clr(trans); cnt = fail = 0;        }    } tr[MAXN * 10];    inline void init() {        for(int i = 0; i < 26; ++i) tr[0].trans[i] = 1;        tr[tot = 1].clear();    }    inline void insert(char * s) {        int u = 1;        int len = strlen(s + 1); mx = max(mx, len);        for(int i = 1; i <= len; ++i) {            if(!tr[u].trans[s[i] - 'a']) tr[tr[u].trans[s[i] - 'a'] = ++tot].clear();            u = tr[u].trans[s[i] - 'a'];         }        tr[u].cnt++;    }    inline void buildfail() {        queue<int> q;        q.push(1);        while(!q.empty()) {            int u = q.front(); q.pop();            for(int i = 0; i < 26; ++i) {                int v = tr[u].fail;                while(!tr[v].trans[i]) v = tr[v].fail;                v = tr[v].trans[i]; int w = tr[u].trans[i];                if(w) tr[w].fail = v, q.push(w), tr[w].cnt += tr[v].cnt;                else tr[u].trans[i] = v;            }        }    }    inline int solve(char *s, int l, int r) {        int now = 1, ans = 0;        for(int i = l; i <= r; ++i) {            now = tr[now].trans[s[i] - 'a'];            ans += tr[now].cnt;        }        return ans;    }}acam;int main() {    //freopen("1.in", "r", stdin);    int n = read(), m = read();    acam.init();    for(int i = 1; i <= n; ++i) scanf("%s", s + 1), acam.insert(s);     acam.buildfail();    scanf("%s", s + 1); int len = strlen(s + 1);    int ans = acam.solve(s, 1, len);    printf("%d\n", ans);    while(m--) {        int pos = read(); char ch = getchar();         int ans1 = acam.solve(s, max(1, pos - mx + 1), min(len, pos + mx - 1));        s[pos] = ch;         int ans2 = acam.solve(s, max(1, pos - mx + 1), min(len, pos + mx - 1));        ans += ans2 - ans1;        cout<<ans<<'\n';    }}
原创粉丝点击