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;
    }
    
  • 相关阅读:
    Selenium2+python自动化-使用JS脚本处理网页滚动条
    Python定时框架 Apscheduler 详解【转】
    转:VMware 15 安装 MAC OS 10.13 原版(详细图文教程)
    Appium+Robotframework实现iOS应用的自动化测试
    在jenkins打开roboframework报告:Opening Robot Framework report failed
    springcloud使用pagehelper 实现分页,及total 数据问题
    日志打印request 和response 内容
    springboot+elasticsearch + rabbitMQ实现全文检索(使用transportClient 实现CRUD)
    springboot+elasticsearch + rabbitMQ实现全文检索(springboot+ES整合)
    springboot+elasticsearch + rabbitMQ实现全文检索(项目搭建)
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/9173311.html
Copyright © 2011-2022 走看看