2022 牛客多校 第三场 H - Hacker

题意

给原串 \(n\) 长度串 \(S\) , 一个 \(m\) 长度的权值数组 \(v\) , \(k\)\(m\) 长度的询问串, 要求每个询问串找一个与原串的公共子串, 使得子串所在段的权值和 ( 询问串和权值数组一一对应 ) 最大

思路

SAM

\(v\) 数组丢到线段树上跑区间子段最大值 (也可以用单调队列)

用原串建立后缀自动机, 询问串到后缀自动机上跑, (失配了就往 fail 树跳, 直到该结点能往下匹配, 如果走到根还失配, 说明完全不匹配, 跳过 ) 同时子串长度, 更新为该节点的 len + 1

代码

#include <bits/stdc++.h>
using i64 = long long;
using pii = std::pair<int,int>;
#define de(x) std::cout << #x << " = " << (x) << std::endl;
constexpr int MOD = 998244353;

namespace SAM {

const int TOT = 1e5 + 6;
const int MAXLEN = TOT * 2;
const i64 SIGMA = 26;
bool vis[MAXLEN] = {false};

struct State {
    int len,link;
    int next[SIGMA];
};

State st[MAXLEN];
int tot = 0;
int last = 0;

void init() {
    for(int i=0;i<tot;++i) {
        st[i].len = 0;
        st[i].link = 0;
        for(int c = 0; c < SIGMA; ++c) {
            st[i].next[c] = 0;
        }
    }
    st[0].len = 0;
    st[0].link = -1;
    tot = 1;
    last = 0;
}

int make_clone(int p,int c) {
    int t = st[p].next[c];
    int clone = tot;
    ++tot;
    st[clone].len = st[p].len + 1;
    for(int i = 0; i < SIGMA; ++i) {
        st[clone].next[i] = st[t].next[i];
    }
    st[clone].link = st[t].link;
    vis[clone] = vis[t];
    for(; p != -1 && st[p].next[c] == t; p = st[p].link) {
        st[p].next[c] = clone;
    }
    return clone;
}

int extend(int c,int last) {
    // if(c >= 'a')
    c -= 'a';

    if(st[last].next[c]) {
        int p = last, t = st[last].next[c];
        int ret = t;
        if(st[p].len + 1 != st[t].len) {
            ret = st[t].link = make_clone(p,c);
        }
        return ret;
    }

    int cur = tot, p;
    ++tot;
    st[cur].len = st[last].len + 1;
    for(p = last; p != -1 && !st[p].next[c]; p = st[p].link) {
        st[p].next[c] = cur;
    }

    if(p == -1) {
        st[cur].link = 0;
    }else {
        int t = st[p].next[c];
        if(st[p].len + 1 == st[t].len) {
            st[cur].link = t;
        }else {
            st[t].link = st[cur].link = make_clone(p,c);
        }
    }
    return cur;
}

int extend(int c) {
    last = extend(c, last);
    return last;
}

void finish() {
    last = 0;
}

}

struct Info {
    i64 ls,rs,sum,v;
    Info(i64 x = 0) {
        if(x > 0) {
            ls = rs = sum = v = x;
        }else {
            sum = x, ls = rs = v = 0;
        }
    }
    friend Info merge(Info x,Info y) {
        Info res;
        res.sum = x.sum + y.sum;
        res.ls = std::max(x.ls, x.sum + y.ls);
        res.rs = std::max(x.rs + y.sum, y.rs);
        res.v = std::max(std::max(x.v, y.v), x.rs + y.ls);
        return res;
    }
};

struct SegT {
    int n;
    std::vector<Info> t;
    SegT(int n,const std::vector<i64> &a) : n(n),t(n * 4) {
        build(1,0,n,a);
    }
    void pull(int p) {
        t[p] = merge(t[p << 1], t[p << 1 | 1]);
    }
    void build(int p,int l,int r,const std::vector<i64> &a) {
        if(r - l == 1) {
            t[p] = Info(a[l]);
            return;
        }
        int mid = l + r >> 1;
        build(p << 1, l, mid, a);
        build(p << 1 | 1, mid, r, a);
        pull(p);
    }

    Info query(int p,int l,int r,int le,int ri) {
        if(ri <= l || r <= le) {
            return Info(0);
        }

        if(le <= l && r <= ri) {
            return t[p];
        }
        int mid = l + r >> 1;
        return merge(query(p << 1, l, mid, le ,ri), query(p << 1 | 1, mid, r, le, ri));
    }
};

void sol() {
    int n,m,k;
    std::cin >> n >> m >> k;
    std::string s;
    std::cin >> s;
    SAM::init();
    for(char c : s) {
        SAM::extend(c);
    }
    SAM::finish();
    std::vector<i64> a(m);
    for(int i=0;i<m;++i) {
        std::cin >> a[i];
    }
    SegT tr(m,a);
    for(int i=0;i<k;++i) {
        std::string t;
        std::cin >> t;
        i64 res = 0;

        int nw = 0, len = 0;
        for(int j=0;j<t.length();++j) {
            while(nw && !SAM::st[nw].next[t[j] - 'a']) {
                nw = SAM::st[nw].link;
                len = SAM::st[nw].len;
            }
            ++len;
            if(SAM::st[nw].next[t[j] - 'a']) nw = SAM::st[nw].next[t[j] - 'a'];
            else continue;
            res = std::max(tr.query(1,0,m,j+1-len,j+1).v, res);
        }
        std::cout << res << '\n';
    }
}

int main(int argc, char *argv[])
{
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);

    // int t;
    // std::cin >> t;
    // while(t --> 0) {
        sol();
    // }
    
    return 0;
}
posted @ 2022-07-27 16:15  LacLic  阅读(66)  评论(0编辑  收藏  举报