• Codeforces 802I - Fake News(hard) 后缀数组+单调栈


    Codeforces 802I - Fake News(hard) 后缀数组+单调栈

    题目思路

    要求求题目不同子串出现次数的平方和。看到本质不同的子串就可以想到SAM+DP或SA+单调栈。这里记录一下SA+单调栈的解决思路。

    首先对字符串 s s s建立后缀数组,并求出 h e i g h t height height数组,考虑 h e i g h t height height数组的意义:
    h e i g h t [ i ] = L C P ( s a [ i ] , s a [ i − 1 ] ) height[i] = LCP(sa[i], sa[i - 1]) height[i]=LCP(sa[i],sa[i1])
    那么显然当 L C P ( s a [ i ] , s a [ i − 1 ] ) < L C P ( s a [ i − 1 ] , s a [ i − 2 ] ) LCP(sa[i], sa[i - 1]) < LCP(sa[i - 1], sa[i - 2]) LCP(sa[i],sa[i1])<LCP(sa[i1],sa[i2])时,某个公共前缀的贡献终止了,此时应当将该公共前缀的贡献统计进答案。这该如何理解?考虑现在 h e i g h t [ i ] ( L C P ) height[i](LCP) height[i](LCP)递增:

    在这里插入图片描述

    如果秃然遇到了一个更小的 L C P LCP LCP

    在这里插入图片描述

    那么此时两个阴影覆盖区域的后缀的前缀都终止了贡献。考虑如何统计答案:将答案 n 2 n^2 n2拆分为 2 × ( i − 1 ) + 1 2 \times (i - 1) + 1 2×(i1)+1,然后单独对 2 × ( i − 1 ) 2 \times (i - 1) 2×(i1)的部分进行计数。

    维护一个 h e i g h t height height递增的单调栈,每次弹元素的时候统计贡献:贡献等于 2 × n × ( n + 1 ) 2 × l e n 2 \times \frac{n \times(n + 1)}{2} \times len 2×2n×(n+1)×len,统计进答案即可。

    Code

    #include 
    #define int long long
    #define endl '\n'
    using namespace std;
    
    const int N = 1e6 + 10;
    
    namespace SA {
        int sa[N], tax[N], pool1[N], pool2[N], height[N];
        int *rnk = pool1, *tp = pool2;
        void sort(int n, int m) {
            for(int i = 0; i <= m; i++) tax[i] = 0;
            for(int i = 1; i <= n; i++) tax[rnk[i]]++;
            for(int i = 1; i <= m; i++) tax[i] += tax[i - 1];
            for(int i = n; i >= 1; i--) sa[tax[rnk[tp[i]]]--] = tp[i];
        }
    
        void build(string str, int n, int m) {
            for(int i = 1; i <= n; i++) rnk[i] = str[i] - '0' + 1, tp[i] = i;
            sort(n, m);
            for(int w = 1, p = 0; p < n; w <<= 1, m = p) {
                p = 0;
                for(int i = 1; i <= w; i++) tp[++p] = n - w + i;
                for(int i = 1; i <= n; i++) if(sa[i] > w) tp[++p] = sa[i] - w;
                sort(n, m);
                swap(tp, rnk);
                rnk[sa[1]] = p = 1;
                for(int i = 2; i <= n; i++) rnk[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w] == tp[sa[i] + w]) ? p : ++p;
            }
            int k = 0;
            for(int i = 1; i <= n; i++) {
                if(rnk[i] == 1) continue;
                if(k) --k;
                for(int j = sa[rnk[i] - 1]; str[i + k] == str[j + k]; ++k);
                height[rnk[i]] = k;
            } // Get the height array (height[i] = lcp(sa[i], sa[i - 1]))
        } 
    
        void reset() {
            memset(sa, 0, sizeof(sa));
            memset(rnk, 0, sizeof(pool1));
            memset(tp, 0, sizeof(pool2));
            memset(tax, 0, sizeof(tax));
            rnk = pool1, tp = pool2;
        }
    }
    
    using SA::sa;
    using SA::rnk;
    using SA::height;
    
    inline void solve() {
        string s; cin >> s;
        int n = s.size();
        SA::build('@' + s, n, 233);
        int ans = n * (n + 1) / 2;
        stack<int> stk;
        for(int i = 2; i <= n + 1; i++) {
            while(stk.size() && height[stk.top()] > height[i]) {
                int y = height[stk.top()]; stk.pop();
                int x = height[i];
                int z = (stk.size() ? height[stk.top()] : 0);
                int len = i - (stk.size() ? stk.top() : 1);
                ans += (y - max(x, z)) * (len * len - len);
            }
            stk.emplace(i);
        }
        cout << ans << endl;
        SA::reset();
    }
    
    signed main(){
        ios_base::sync_with_stdio(false), cin.tie(0);
        int t = 1; cin >> t;
        while(t--) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
  • 相关阅读:
    Sharding JDBC案例实战
    Python每日一练 01
    linux rsyslog日志采集格式设定三
    6 个意想不到的 JavaScript 问题
    柯桥在PPT中如何制作翻书动画?
    向日葵远程控制为何采用BGP服务器?自动最优路线、跨运营商高速传输
    DIY官网可视化工具打造UNIAPP-uviewUI可视化
    vue 预览 有token验证的 doc、docx、pdf、xlsx、csv、图片 并下载
    基于 CoreDNS 和 K8s 构建云原生场景下的企业级 DNS
    【无标题】
  • 原文地址:https://blog.csdn.net/yanweiqi1754989931/article/details/127778447