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;
    }
    
  • 相关阅读:
    sharepoint 2007 升级到 sharepoint 2013
    sharepoint 2010中启用RBS及所遇问题
    sharepoint 读取文件夹中所有的数据
    脚本设置ip&自动获取ip
    window 2008 r2 每隔一小时都要重启一次解决办法
    sharepoint 弹出框
    sharepoint powershell 根据报错的GUID查询错误
    java中switch选择结构
    mysql查看表字段相关信息
    mac系统 -postman发送http请求
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/9173311.html
Copyright © 2011-2022 走看看