• [BZOJ3238][Ahoi2013]差异


    3238: [Ahoi2013]差异

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 3394  Solved: 1542
    [Submit][Status][Discuss]

    Description

    Input

    一行,一个字符串S

    Output

    一行,一个整数,表示所求值

    Sample Input

    cacao

    Sample Output


    54

    HINT



    2<=N<=500000,S由小写英文字母组成

    先把答案加的那部分弄出来,可以$O(1)$计算。。

    然后剩下的部分可以通过建反串的后缀自动机,那么$Parent$树就是原串的后缀树。。

    然后树形DP即可

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn = 500000 + 10;
    struct State {
        int len, link, tot;
        int son[26];
    }st[maxn * 2];
    int cnt, last;
    void sam_init() {
        cnt = last = 0;
        st[0].len = 0;
        st[0].link = -1;
        st[0].tot = 0;
        memset(st[0].son, 0, sizeof(st[0].son));
    }
    void sam_extend(char c) {
        int cur = ++cnt, idx = c - 'a';
        st[cur].len = st[last].len + 1;
        memset(st[cur].son, 0, sizeof(st[cur].son));
        st[cur].tot = 1;
        int p;
        for (p = last; p != -1 && !st[p].son[idx]; p = st[p].link)
            st[p].son[idx] = cur;
        if (p == -1) st[cur].link = 0;
        else {
            int q = st[p].son[idx];
            if (st[p].len + 1 == st[q].len) st[cur].link = q;
            else {
                int clone = ++cnt;
                st[clone].len = st[p].len + 1;
                memcpy(st[clone].son, st[q].son, sizeof(st[q].son));
                st[clone].link = st[q].link;
                st[clone].tot = 0;
                for (; p != -1 && st[p].son[idx] == q; p = st[p].link)
                    st[p].son[idx] = clone;
                st[q].link = st[cur].link = clone;
            }
        }
        last = cur;
    }
    char S[maxn];
    int len;
    struct Edge {
        int to, next;
        Edge() {}
        Edge(int _t, int _n) : to(_t), next(_n) {}
    }e[maxn * 2];
    int fir[maxn * 2] = { 0 }, ecnt = 0;
    inline void add(int u, int v) {
        e[++ecnt] = Edge(v, fir[u]); fir[u] = ecnt;
    }
    void build() {
        for (int i = 1; i <= cnt; i++)
            add(st[i].link, i);
    }
    long long ans;
    void dfs(int u) {
        for (int v, i = fir[u]; i; i = e[i].next) {
            v = e[i].to;
            dfs(v);
            ans -= 2LL * st[u].len * st[u].tot * st[v].tot;
            st[u].tot += st[v].tot;
        }
    }
    int main() {
        scanf("%s", S);
        sam_init();
        len = strlen(S);
        for (int i = 0; i < len; i++)
            sam_extend(S[len - i - 1]);
        build();
        ans = (long long)(len + 1) * len * (len - 1) / 2;
        dfs(0);
        printf("%lld
    ", ans);
        return 0;
    }

     时隔两年来更新

    前面两项可以$O(1)$计算

    主要是计算后面一项

    注意到$sa$数组是一个$1$到$n$的全排列且$lcp(T_i,T_j)=lcp(T_j,T_i)$

    因此$sum_{1le i<jle n}lcp(T_i,T_j)=sum_{1le i<jle n}lcp(T_{sa[i]},T_{sa[j]})$

    而$lcp(T_{sa[i]},T_{sa[j]})=min_{i+1le kle j}(height[k])$

    因此原式可变形为$sum_{2le ile jle n}min_{ile kle j}(height[k])$

    可以考虑计算每个$height[i]$作为最小值时被多少个区间包含

    显然可以用单调栈维护

    注意一下相等数值之间的影响

    时间复杂度$O(nlogn)$

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn = 500000 + 10;
    char s[maxn];
    int n, m;
    int sa[maxn], rank[maxn], height[maxn];
    int tax[maxn], tp[maxn];
    void qsort(){
        for(int i = 1; i <= m; i++) tax[i] = 0;
        for(int i = 1; i <= n; i++) tax[rank[i]]++;
        for(int i = 2; i <= m; i++) tax[i] += tax[i - 1];
        for(int i = n; i; i--) sa[tax[rank[tp[i]]]--] = tp[i];
    }
    bool cmp(int *a, int l, int r, int w){
        return a[l] == a[r] && a[l + w] == a[r + w];
    }
    void suffix_sort(){
        m = 128;
        for(int i = 1; i <= n; i++) rank[i] = s[i];
        for(int i = 1; i <= n; i++) tp[i] = i;
        qsort();
        for(int k = 1, p = 0; p < n; m = p, k <<= 1){
            p = 0;
            for(int i = 1; i <= k; i++) tp[++p] = n - k + i;
            for(int i = 1; i <= n; i++) if(sa[i] > k) tp[++p] = sa[i] - k;
            qsort();
            swap(tp, rank);
            p = rank[sa[1]] = 1;
            for(int i = 2; i <= n; i++)
                rank[sa[i]] = cmp(tp, sa[i - 1], sa[i], k) ? p : ++p;
        }
        for(int i = 1, j, k = 0; i <= n; height[rank[i++]] = k)
            for(k ? k-- : 0, j = sa[rank[i] - 1]; s[i + k] == s[j + k]; k++);
    }
    int f[maxn], g[maxn], sta[maxn], top;
    void calc(){
        ll ans = (ll)n * (n - 1) * (n + 1) / 2;
        f[2] = 1;
        top = 0;
        for(int i = 2; i <= n; i++){
            while(top && height[sta[top]] > height[i]) top--;
            if(!top) f[i] = i - 1;
            else f[i] = i - sta[top];
            sta[++top] = i;
        }
        g[n] = 1;
        top = 0;
        for(int i = n; i >= 2; i--){
            while(top && height[sta[top]] >= height[i]) top--;
            if(!top) g[i] = n - i + 1;
            else g[i] = sta[top] - i;
            sta[++top] = i;
        }
        for(int i = 2; i <= n; i++)
            ans -= (ll)2 * f[i] * g[i] * height[i];    
        printf("%lld
    ", ans);
    }
    int main(){
        scanf("%s", s + 1);
        n = strlen(s + 1);
        suffix_sort();
        calc();
        return 0;
    }
  • 相关阅读:
    Different AG groups have the exactly same group_id value if the group names are same and the ‘CLUSTER_TYPE = EXTERNAL/NONE’
    An example of polybase for Oracle
    use azure data studio to create external table for oracle
    Missing MSI and MSP files
    You may fail to backup log or restore log after TDE certification/key rotation.
    Password is required when adding a database to AG group if the database has a master key
    Use KTPASS instead of adden to configure mssql.keytab
    ardunio+舵机
    android webview 全屏100%显示图片
    glide 长方形图片显示圆角问题
  • 原文地址:https://www.cnblogs.com/ruoruoruo/p/7604164.html
Copyright © 2020-2023  润新知