「十二省聯考 2019」字符串問題

「十二省聯考 2019」字符串問題

解題思路node

傻逼題..c++

考慮問題轉化爲一個A串向其支配的全部B串的後綴A串連邊,若是有環答案 \(-1\) 不然是這個 \(\text{DAG}\) 上最長路徑,直接建圖是 \(n^2\) 的,考慮優化建圖便可。git

因爲 \(A,B\) 都是原串的一個子串,那麼對原串的反串建 SAM,一個子串的後綴就是其所在節點上比它長的串以及,其子樹裏的全部串。優化

首先將全部 \(A,B\) 串在 SAM上用倍增定位並新建節點,把SAM上每一個節點拆成入點和出點,對於SAM每個節點上的 \(A,B\) 串節點按照長度排序和入點出點連成一條鏈,每一個點再向其孩子連邊。此時直接讓 \(A\) 串對應點和 \(B\) 串對應點連邊便可。因爲要保證 \(A\) 串必需要通過其支配的 \(B\) 串才能到另一個 \(A\) 串,因此不要把 \(A\) 串的貢獻直接記在鏈上的節點,再新建一個節點記在這個節點上面而後讓原來的節點連一條邊到它便可,總複雜度 \(\mathcal O(nlogn)\)spa

具體建邊看代碼吧,直接講可能不太能講清楚,反正這個題挺無腦的,下午拿到題40分鐘就寫完過了。code

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;
}
相關文章
相關標籤/搜索