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;
}
Living with bustle, hearing of isolation.