「十二省联考 2019」字符串问题
「十二省联考 2019」字符串问题
解题思路
傻逼题..
考虑问题转化为一个A串向其支配的所有B串的后缀A串连边,如果有环答案 \(-1\) 否则是这个 \(\text{DAG}\) 上最长路径,直接建图是 \(n^2\) 的,考虑优化建图即可。
由于 \(A,B\) 都是原串的一个子串,那么对原串的反串建 SAM,一个子串的后缀就是其所在节点上比它长的串以及,其子树里的所有串。
首先将所有 \(A,B\) 串在 SAM上用倍增定位并新建节点,把SAM上每个节点拆成入点和出点,对于SAM每一个节点上的 \(A,B\) 串节点按照长度排序和入点出点连成一条链,每个点再向其孩子连边。此时直接让 \(A\) 串对应点和 \(B\) 串对应点连边即可。由于要保证 \(A\) 串必须要经过其支配的 \(B\) 串才能到另外一个 \(A\) 串,所以不要把 \(A\) 串的贡献直接记在链上的节点,再新建一个节点记在这个节点上面然后让原来的节点连一条边到它即可,总复杂度 \(\mathcal O(nlogn)\)。
具体建边看代码吧,直接讲可能不太能讲清楚,反正这个题挺无脑的,下午拿到题40分钟就写完过了。
code
/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 2000005;
int na, nb;
namespace graph{
queue<int> q;
vector<int> g[N];
int deg[N], n; ll val[N], dis[N];
inline void addedge(int x, int y){
g[x].push_back(y), deg[y]++, n = max(n, max(x, y));
}
inline void solve(){
for(int i = 1; i <= n; i++) if(!deg[i]) q.push(i);
int tot = 0;
for(; !q.empty(); q.pop()){
int u = q.front();
dis[u] += val[u], tot++;
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i];
dis[v] = max(dis[v], dis[u]);
if(!--deg[v]) q.push(v);
}
}
if(tot != n) return (void) (puts("-1"));
ll ans = 0;
for(int i = 1; i <= n; i++) ans = max(ans, dis[i]);
printf("%lld\n", ans);
}
inline void clear(){
for(int i = 1; i <= n; i++)
deg[i] = dis[i] = val[i] = 0, g[i].clear();
n = 0;
}
}
inline bool cmp(pair<int, int> A, pair<int, int> B){
return A.first != B.first ? A.first < B.first : A.second > B.second;
}
namespace SAM{
vector<pair<int, int> > s[N];
vector<int> g[N];
int len[N], pos[N], nid[N], f[N][22], fa[N], ch[N][26], size = 1, tail = 1, total;
inline int newnode(int x){ return len[++size] = x, size; }
inline void ins(int c, int id){
int p = tail, np = newnode(len[p] + 1); pos[id] = np;
for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if(!p) return (void) (fa[np] = 1, tail = np);
int q = ch[p][c];
if(len[q] == len[p] + 1) fa[np] = q;
else{
int nq = newnode(len[p] + 1);
fa[nq] = fa[q], fa[q] = fa[np] = nq;
for(int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
}tail = np;
}
inline void dfs(int u){
f[u][0] = fa[u];
for(int i = 1; i <= 20; i++) f[u][i] = f[f[u][i-1]][i-1];
for(int i = 0; i < (int) g[u].size(); i++)
graph::addedge(u + size, g[u][i]), dfs(g[u][i]);
}
inline void addedge1(){
for(int i = 2; i <= size; i++) g[fa[i]].push_back(i);
dfs(1);
}
inline void pushnode(int l, int r, int id){
int x = pos[l];
for(int i = 20; ~i; i--)
if(len[f[x][i]] >= r - l + 1) x = f[x][i];
s[x].push_back(make_pair(r - l + 1, id));
}
inline void addedge2(){
for(int i = 1; i <= size; i++){
sort(s[i].begin(), s[i].end(), cmp);
for(int j = 0; j < (int) s[i].size(); j++){
int x = s[i][j].second;
nid[x] = x + size * 2, x += size * 2;
if(j == 0) graph::addedge(i, x);
if(j == (int) s[i].size() - 1) graph::addedge(x, i + size);
else graph::addedge(x, s[i][j+1].second + size * 2);
if(x <= size * 2 + na){
++total;
int u = size * 2 + na + nb + total;
graph::addedge(x, u);
graph::val[u] = s[i][j].first, nid[x-2*size] = u;
}
}
if(!(int) s[i].size()) graph::addedge(i, i + size);
}
}
inline void clear(){
for(int i = 1; i <= size; i++){
memset(ch[i], 0, sizeof(ch[i]));
fa[i] = len[i] = 0, g[i].clear(), s[i].clear();
}
size = tail = 1, total = 0;
}
}
char str[N];
inline void realmain(){
scanf("%s", str + 1); int n = strlen(str + 1);
for(int i = n; i; i--) SAM::ins(str[i] - 'a', i);
SAM::addedge1();
read(na);
for(int i = 1, l, r; i <= na; i++)
read(l), read(r), SAM::pushnode(l, r, i);
read(nb);
for(int i = 1, l, r; i <= nb; i++)
read(l), read(r), SAM::pushnode(l, r, na + i);
SAM::addedge2();
int m; read(m);
for(int i = 1, x, y; i <= m; i++){
read(x), read(y);
graph::addedge(SAM::nid[x], SAM::nid[y+na]);
}
graph::solve();
for(int i = 1; i <= na + nb; i++) SAM::nid[i] = 0;
for(int i = 1; i <= n; i++) SAM::pos[i] = 0;
SAM::clear(), graph::clear();
}
int main(){
int T; read(T); while(T--) realmain();
return 0;
}