Common Substrings POJ - 3415 (suffix automaton)

Common Substrings

\[ Time Limit: 5000 ms\quad Memory Limit: 65536 kB \]

The meaning of problems

Given two strings, string length requires two common sub-strings is not less than \ (K \) number pairs.

Thinking

For \ (S \) sequence constructs suffix automaton, then use \ (V \ in u'son \) , \ (DP [U] + DP = [V] \) is obtained for each node \ (endpos \) size.

With \ (T \) train running longest common consecutive sub-string on an automatic machine, assuming now \ (T \) longest partial match the string is \ (T \) , stopped on the automaton \ (P \) node. To prevent duplicate counting, we are asking is that the \ (t \) of all suffixes \ (S \) how much the position of the match.

This calculation method is \ (\ DP SUM [I] * (the LCS-max (. 1-K, father.len)) \) . In \ (p \) node, \ (LCS \) is updated every time we answer \ (RES \) , next to \ (p \) is \ (father \) is updated, \ (LCS \) is \ (i.len \)

Examples of such
\ (xx \\ xx \)
when the second matching string, the first match \ (X \) _. The second match to \ (xx \) , then we continue to update _ \ (the X-\) answers.

But if violence update every time up, a time out, we found that only every match just to \ (p \) answer node with \ (res \) , whereas \ (p \) to update the upward node contributions are fixed, so we can first find all of \ (p \) contribution to the node, and then use \ (cnt [i] \) represents \ (i \) node is under renewed several times, calculate backwards compressing the number of updates.

#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pii        pair<int, int>
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 2e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m, k;
int cas, tol, T;

struct Sam {
    struct Node {
        int next[55];
        int fa, len;
        void init() {
            mes(next, 0);
            fa = len = 0;
        }
    } node[maxn];
    ll dp[maxn], cnt[maxn];
    int sz, last;
    void init() {
        last = sz = 1;
        mes(dp, 0);
        node[sz].init();
    }
    void insert(int k) {
        int p = last, np = last = ++sz;
        dp[np] = 1;
        node[np].init();
        node[np].len = node[p].len+1;
        for(; p&&!node[p].next[k]; p=node[p].fa)
            node[p].next[k] = np;
        if(p == 0) {
            node[np].fa = 1;
        } else {
            int q = node[p].next[k];
            if(node[q].len == node[p].len+1) {
                node[np].fa = q;
            } else {
                int nq = ++sz;
                node[nq] = node[q];
                node[nq].len = node[p].len+1;
                node[np].fa = node[q].fa = nq;
                for(; p&&node[p].next[k]==q; p=node[p].fa)
                    node[p].next[k] = nq;
            }
        }
    }
    int tax[maxn], gid[maxn];
    void handle() {
        for(int i=0; i<=sz; i++)    tax[i] = cnt[i] = 0;
        for(int i=1; i<=sz; i++)    tax[node[i].len]++;
        for(int i=1; i<=sz; i++)    tax[i] += tax[i-1];
        for(int i=1; i<=sz; i++)    gid[tax[node[i].len]--] = i;
        for(int i=sz; i>=1; i--) {
            int u = gid[i];
            int fa = node[u].fa;
            dp[fa] += dp[u];
        }
    }
    void solve(char *s, int k) {
        int len = strlen(s+1);
        int p = 1;
        ll res = 0, ans = 0;
        for(int i=1; i<=len; i++) {
            int nst;
            if('a'<=s[i] && s[i]<='z')  nst = s[i]-'a'+1;
            else    nst = s[i]-'A'+1+26;
            while(p && !node[p].next[nst]) {
                p = node[p].fa;
                res = node[p].len;
            }
            if(p == 0) {
                p = 1;
                res = 0;
            } else {
                p = node[p].next[nst];
                res++;
            }
            if(res >= k) {
                ans += dp[p]*(res - max(node[node[p].fa].len, k-1));
                if(node[node[p].fa].len >= k)
                    cnt[node[p].fa]++;
            }
        }
        for(int i=sz; i>=1; i--) {
            int u = gid[i];
            ans += dp[u]*cnt[u]*(node[u].len - max(node[node[u].fa].len, k-1));
            if(node[node[u].fa].len >= k)
                cnt[node[u].fa] += cnt[u];
        }
        printf("%lld\n", ans);
    }
} sam;
char s[maxn], t[maxn];

int main() {
    while(scanf("%d", &k), k) {
        sam.init();
        scanf("%s%s", s+1, t+1);
        int slen = strlen(s+1);
        for(int i=1; i<=slen; i++) {
            int nst;
            if('a'<=s[i] && s[i]<='z')  nst = s[i]-'a'+1;
            else    nst = s[i]-'A'+1+26;
            sam.insert(nst);
        }
        sam.handle();
        sam.solve(t, k);
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/Jiaaaaaaaqi/p/10953056.html