zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第八场) H Hard String Problem

    题解:(bin) 巨的题解其实已经很详细了,这里讲几个可能会踩到的坑,(kmp) 求最小循环节时我们要先把原来的串翻倍,也就是在串后面再接上这个串本身,因为 (kmp) 中的 (len - next[len]) 所得出来的循环节长度是可能的最小循环节长度,但我们要求的是准确的,比如 (abcdabc) ,如果直接用 (kmp) 求的话,得到的最小循环节会是 (abcd) , 展开后为 (abcdabcdabcd) , 而原串展开后为 (abcdabcabcdabc) ,有明显的不同,然后我们将每个循环节最小表示,判断循环节是否相同,之后就是按 (bin) 巨的题解将字符串展开四倍,最短串展开到大于等于最长串的四倍,之后用广义 (SAM) 求解即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn = 6e6 + 50;
    const int maxn2 = 3e5 + 50;
    string ss[maxn2], s;
    int knex[maxn];
    int n;
    void getNext(int id){
        int tlen = ss[id].size();
        int j = 0, k = -1;
        knex[0] = -1;
        while(j < tlen){
            if(k == -1 || ss[id][j] == ss[id][k]) knex[++j] = ++k;
            else k = knex[k];
        }
    }
     
    int get_min(int id){
        int len = ss[id].size();
        int i = 0, j = 1, k = 0, t;
        while(i < len && j < len && k < len){
            t = ss[id][(i + k) % len] - ss[id][(j + k) % len];
            if(!t) k++;
            else {
                if(t > 0) i += k + 1;
                else j += k + 1;
                if(i == j) j++;
                k = 0;
            }
        }
        return min(i, j);
    }
     
    struct state
    {
        int len, link, nex[26];
    } st[maxn];
    int sz, last;
     
    void sam_init(){
        st[0].len = 0;
        st[0].link = -1;
        sz = 1, last = 0;
    }
     
    void sam_extend(int x){
        int cur = sz++;
        st[cur].len = st[last].len + 1;
        int p = last;
        while(p != -1 && !st[p].nex[x]){
            st[p].nex[x] = cur;
            p = st[p].link;
        }
        if(p == -1) st[cur].link = 0;
        else {
            int q = st[p].nex[x];
            if(st[p].len + 1 == st[q].len){
                st[cur].link = q;
            } else {
                int clone = sz++;
                st[clone].len = st[p].len + 1;
                st[clone].link = st[q].link;
                for(int i = 0; i < 26; i++){st[clone].nex[i] = st[q].nex[i];}
                while(p != -1 && st[p].nex[x] == q){
                    st[p].nex[x] = clone;
                    p = st[p].link;
                }
                st[q].link = st[cur].link = clone;
            }
        }
        last = cur;
    }
     
    LL val[maxn];
     
    bool cmp(const string s1, const string s2){
        return s1.size() < s2.size();
    }
    
    int vis[maxn];
    int main()
    {
        cin >> n;
        for(int i = 1; i <= n; i++){
            cin >> ss[i];
            ss[i] += ss[i];
            getNext(i);
            int len = ss[i].size();
            len = len - knex[len];
            ss[i] = ss[i].substr(0, len);
        }
        for(int i = 1; i <= n; i++){
            int st = get_min(i);
            int len = ss[i].size();
            s = "";
            for(int j = 0; j < len; j++){
                s += ss[i][(st + j) % len];
            }
            ss[i] = s;
        }
         
        int flag = 1;
        for(int i = 2; i <= n; i++){
            if(ss[i] != ss[i - 1]) {
                flag = 0;
                break;
            }
        }
        if(flag){
            cout << -1 << '
    ';
            return 0;
        }
        sort(ss + 1, ss + n + 1, cmp);
        for(int i = 2; i <= n; i++){
            s = ss[i];
            for(int j = 1; j <= 3; j++) ss[i] += s;
        }
        s = ss[1];
        while(ss[1].size() < ss[n].size()){
            ss[1] += s;
        }
        sam_init();
        for(int i = 1; i <= n; i++){
            int len = ss[i].size();
            last = 0;
            for(int j = 0; j < len; j++){
                sam_extend(ss[i][j] - 'a');
            }
        }
        for(int i = 1; i <= n; i++){
            int len = ss[i].size();
            int p = 0;
            for(int j = 0; j < len; j++){
                p = st[p].nex[ss[i][j] - 'a'];
                int u = p;
                while(vis[u] != i && u != 0) vis[u] = i, val[u]++, u = st[u].link;
            }
        }
        LL ans = 0;
        for(int i = 1; i < sz; i++){
            if(val[i] == n) ans += st[i].len - st[st[i].link].len;
        }
        cout << ans << '
    ';
    }
    
  • 相关阅读:
    # 2018-2019-1 20165206 《信息安全系统设计基础》第1周学习总结
    20165206 2017-2018-2《Java程序设计》课程总结
    2017-2018-2 20165206 实验五《网络编程与安全》实验报告
    20165206第4次实验《Android程序设计》实验报告
    同源策略、跨域解决方案
    盒子模型,块级元素和行内元素
    http常见错误
    深入理解 JavaScript 事件循环(一)— event loop
    git常用指令
    js 常用方法
  • 原文地址:https://www.cnblogs.com/PCCCCC/p/13435739.html
Copyright © 2011-2022 走看看