zoukankan      html  css  js  c++  java
  • CF700E Cool Slogans

    题意

    给出一个长度为 (n) 的字符串 (s[1]),由小写字母组成。定义一个字符串序列 (s[1....k]) ,满足性质:(s[i])(s[i-1]) ((i ge 2)) 中出现至少两次(位置可重叠),问最大的 (k) 是多少,使得从 (s[1]) 开始到 (s[k]) 都满足这样一个性质。

    Sol

    某模拟赛出了这样一道题
    然后因为测试没开无限栈,没有AC

    建立后缀自动机,那么每个点就是字符串中的一个子串
    (f[i]) 表示以 (i) 这个子串结尾的最大的答案
    显然在 (parent) 树上,(f[i]) 可以由父亲转移而来
    然后考虑可以接在什么样的串后面
    如果 (i) 可以接在 (j) 后面,那么 (i) 也可以接在 (j) 的某个前缀(包括自己)的后面,并且这个前缀的某个后缀就是 (i)
    这其实就是 (parent) 树上的祖先和后代的关系

    怎么样找到这样一个点?
    假设 (i) 要找到一个 (j)
    显然 (j)(right) 集合包含 (i) 的集合,不论 (i) 出现在 (right) 集合的那个位置上,它始终含有 (j) 这个子串,并且有 (ge2)
    所以 (j) 只要满足 (i) 的任意一个位置 (pos)
    使得 (j)(right) 集合有 ([pos-len_i+len_j,pos-1]) 区间内的元素,并且 (j)(i) 的祖先即可
    (right) 集合和查询直接线段树合并+查询即可

    暴力找显然不划算
    转移都出来了,那么 (f) 显然是从祖先到后代不降的
    显然如果 (j) 满足 (i) 的要求,那么 (j) 的祖先显然也满足,所以可以倍增找
    复杂度 (O(nlog_n^2n))

    或者是直接在一条链上 (two-points) 即可
    复杂度 (O(nlog_nn))

    # include <bits/stdc++.h>
    # define IL inline
    # define RG register
    # define Fill(a, b) memset(a, b, sizeof(a))
    # define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
    using namespace std;
    typedef long long ll;
    
    IL int Input(){
        RG int x = 0, z = 1; RG char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        return x * z;
    }
    
    const int maxn(4e5 + 5);
    
    int n, tot, last, trans[26][maxn], fa[maxn], len[maxn];
    int first[maxn], nxt[maxn], rt[maxn], sz[maxn * 20], cnt, ls[maxn * 20], rs[maxn * 20];
    int nt[maxn], fp[maxn], f[maxn], pos[maxn], ans;
    char s[maxn];
    
    IL void Modify(RG int &x, RG int l, RG int r, RG int p){
        if(!x) x = ++cnt;
        ++sz[x];
        if(l == r) return;
        RG int mid = (l + r) >> 1;
        p <= mid ? Modify(ls[x], l, mid, p) : Modify(rs[x], mid + 1, r, p);
    }
    
    IL int Merge(RG int x, RG int y){
        if(!x || !y) return x + y;
        RG int z = ++cnt;
        sz[z] = sz[x] + sz[y];
        ls[z] = Merge(ls[x], ls[y]);
        rs[z] = Merge(rs[x], rs[y]);
        return z;
    }
    
    IL int Query(RG int x, RG int l, RG int r, RG int ql, RG int qr){
        if(!x || l > r) return 0;
        if(ql <= l && qr >= r) return sz[x];
        RG int mid = (l + r) >> 1, sum = 0;
        if(ql <= mid) sum = Query(ls[x], l, mid, ql, qr);
        if(qr > mid) sum += Query(rs[x], mid + 1, r, ql, qr);
        return sum;
    }
    
    IL void Extend(RG int c, RG int id){
        RG int p = last, np = ++tot;
        len[last = np] = len[p] + 1, pos[np] = id;
        while(p && !trans[c][p]) trans[c][p] = np, p = fa[p];
        if(!p) fa[np] = 1;
        else{
            RG int q = trans[c][p];
            if(len[q] == len[p] + 1) fa[np] = q;
            else{
                RG int nq = ++tot;
                fa[nq] = fa[q], len[nq] = len[p] + 1;
                for(RG int i = 0; i < 26; ++i) trans[i][nq] = trans[i][q];
                fa[np] = fa[q] = nq;
                while(p && trans[c][p] == q) trans[c][p] = nq, p = fa[p];
            }
        }
        Modify(rt[last], 1, n, id);
    }
    
    IL void Dfs1(RG int u){
        for(RG int v = first[u]; v; v = nxt[v]){
            Dfs1(v);
            rt[u] = Merge(rt[u], rt[v]);
            if(!pos[u]) pos[u] = pos[v];
        }
    }
    
    IL void Dfs2(RG int u){
        fp[u] = 1;
        if(u != 1){
            if(fa[u] == 1) f[u] = 1;
            else{
                RG int p = fp[fa[u]]; f[u] = f[fa[u]];
                while(p != u && Query(rt[p], 1, n, pos[u] - len[u] + len[p], pos[u] - 1)){
                    f[u] = max(f[u], f[fp[u] = p] + 1);
                    p = nt[p];
                }
            }
        }
        for(RG int v = first[u]; v; v = nxt[v]) nt[u] = v, Dfs2(v);
    }
    
    int main(){
        n = Input(), scanf(" %s", s + 1), tot = last = 1;
        for(RG int i = 1; i <= n; ++i) Extend(s[i] - 'a', i);
        for(RG int i = 1; i <= tot; ++i) nxt[i] = first[fa[i]], first[fa[i]] = i;
        Dfs1(1), Dfs2(1);
        for(RG int i = 1; i <= tot; ++i) ans = max(ans, f[i]);
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    C#函数式编程
    三种观察者模式的C#实现
    使用C#设计Fluent Interface
    02.Python网络爬虫第二弹《http和https协议》
    03.Python网络爬虫第一弹《Python网络爬虫相关基础概念》
    第七章:Python基础のXML操作和面向对象(一)
    第五章:Python基础の生成器、迭代器、序列化和虚拟环境的应用
    第六章:Python基础の反射与常用模块解密
    第四章:Python基础の快速认识內置函数和操作实战
    第三章:Python基础の函数和文件操作实战
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/9173311.html
Copyright © 2011-2022 走看看