luoguP4696 [CEOI2011]Matching KMP+树状数组

可以非常轻易的将题意转化为有多少子串满足排名相同

注意到$KMP$算法只会在当前字符串的某尾添加和删除字符

因此,如果添加和删除后面的字符对于前面的字符没有影响时,我们可以用$KMP$来模糊匹配

 

对于本题而言,在末尾插入一个字符时,如果$S$串和$T$串中这两个字符的排名一样,那么它们对前面的影响也是一样的

因此,插入或者删除字符时,后面的字符如果排名一样,可以任何对前面没有影响

反之,如果不一样,那么无法匹配

所以,这满足模糊匹配的条件

 

我们可以拿树状数组来维护插入和删除

由于$next[i] \leq next[i - 1] + 1$,因此分析一下复杂度不会超过$O(n \log n)$

好像带了大常数......

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
namespace remoon {
    #define ri register int
    #define rep(iu, st, ed) for(ri iu = st; iu <= ed; iu ++)
    #define drep(iu, ed, st) for(ri iu = ed; iu >= st; iu --)    
    #define gc getchar
    inline int read() {
        int p = 0, w = 1; char c = gc();
        while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
        while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
        return p * w;
    }
}
using namespace std;
using namespace remoon;

const int sid = 1005000;

int n, m, cm, tot;
int ans[sid], nxt[sid], pre[sid];
int t[sid], p[sid], h[sid], T[sid];

inline void upd(int o, int v) {
    for(ri i = o; i <= m; i += i & (-i)) 
        t[i] += v;
}

inline int qry(int o) {
    int ret = 0;
    for(ri i = o; i; i -= i & (-i))
        ret += t[i];
    return ret;
}

void Solve() {
    rep(i, 1, n)
        pre[i] = qry(p[i]), upd(p[i], 1);
    pre[n + 1] = -1;
        
    rep(i, 1, m) t[i] = 0;
    for(ri i = 2, j = 0; i <= n; i ++) 
    {
        while(j && qry(p[i]) != pre[j + 1]) 
        {
            for(ri k = i - j; k < i - nxt[j]; k ++) 
                upd(p[k], -1);
            j = nxt[j];
        }
        if(qry(p[i]) == pre[j + 1]) j ++, upd(p[i], 1); 
        nxt[i] = j;
    }
    
    rep(i, 1, m) t[i] = 0;
    for(ri i = 1, j = 0; i <= m; i ++) 
    {
        while(j && qry(h[i]) != pre[j + 1]) 
        {    
            for(ri k = i - j; k < i - nxt[j]; k ++)
                upd(h[k], -1);
            j = nxt[j];
        }
        if(qry(h[i]) == pre[j + 1]) j ++, upd(h[i], 1);
        if(j == n) ans[++ tot] = i - n + 1;
    }
}

int main() {
    
    n = read(); m = read();
    rep(i, 1, n) p[read()] = i;
    rep(i, 1, m) T[i] = h[i] = read();
    
    sort(T + 1, T + m + 1);
    cm = unique(T + 1, T + m + 1) - T - 1;
    rep(i, 1, m) h[i] = lower_bound(T + 1, T + cm + 1, h[i]) - T;
    
    Solve();
    printf("%d\n", tot);
    rep(i, 1, tot) printf("%d ", ans[i]);
    printf("\n");
    return 0;
}

 

posted @ 2018-11-12 21:38  remoon  阅读(357)  评论(0编辑  收藏  举报