zoukankan      html  css  js  c++  java
  • [二分][后缀数组]luogu P2463 [SDOI2008]Sandy的卡片

    题面

    https://www.luogu.com.cn/problem/P2463

    求 N 个串中有多少个子串的相邻差值相同

    分析

    解题思路还是很清晰的,可以发现无论如何增减数字,各子串中的相对大小不变

    所以把原串 a[i] 转化为 b[i]=a[i+1]-a[i] (i<m)

    然后找相同的一段子串,是比较明显的SA了,把各串用分割符拼接成一个串就行

    最后通过 height 数组的性质,二分答案并找到 height 的一段连续区间包含所有串而且最小值大于等于二分值即可

    代码

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int N=1e3+10;
    int n,m,cnt,cut=1865,l,r;
    int v[110],s[110*N],x[110*N],y[110*N],sa[110*N],id[110*N],rk[110*N],height[110*N],c[110*N],a[N];
    bool used[N];
    
    void Suffix_Array(int n,int *s,int *sa,int *rk) {
        int m=cut-1,cnt;
        for (int i=0;i<=m;i++) c[i]=0;
        for (int i=1;i<=n;i++) c[x[i]=s[i]]++;
        for (int i=1;i<=m;i++) c[i]+=c[i-1];
        for (int i=n;i;i--) sa[c[x[i]]--]=i;
        for (int j=1;j<=n;j<<=1) {
            cnt=0;
            for (int i=n-j+1;i<=n;i++) y[++cnt]=i;
            for (int i=1;i<=n;i++) if (sa[i]>j) y[++cnt]=sa[i]-j;
            for (int i=0;i<=m;i++) c[i]=0;
            for (int i=1;i<=n;i++) c[x[i]]++;
            for (int i=1;i<=m;i++) c[i]+=c[i-1];
            for (int i=n;i;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0;
            swap(x,y);cnt=x[sa[1]]=1;
            for (int i=2;i<=n;i++) x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[min(sa[i-1]+j,n+1)]==y[min(sa[i]+j,n+1)])?cnt:++cnt;
            m=cnt;if (m==n) break;
        }
        for (int i=1;i<=n;i++) rk[sa[i]]=i;
    }
    
    void Get_Height(int n,int *s,int *sa,int *rk,int *height) {
        int z=0;
        for (int i=1;i<=n;i++) {
            if (rk[i]==1) {height[1]=0;continue;}
            if (z) z--;
            while (i+z<=n&&sa[rk[i]-1]+z<=n&&s[i+z]==s[sa[rk[i]-1]+z]) z++;
            height[rk[i]]=z;
        }
    }
    
    bool Check(int x) {
        int m=0;
        for (int i=1;i<=cnt;i++) {
            if (height[i]<x) {
                for (int j=1;j<=m;j++) used[a[j]]=0;m=0;
            }
            if (!used[id[sa[i]]]) used[a[++m]=id[sa[i]]]=1;
            if (m==n) {for (int j=1;j<=m;j++) used[a[j]]=0;return 1;}
        }
        return 0;
    }
    
    int main() {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) {
            scanf("%d",&m);scanf("%d",&v[1]);r=max(r,m);
            for (int j=2;j<=m;j++) scanf("%d",&v[j]),v[j-1]=v[j]-v[j-1];
            for (int j=1;j<m;j++) s[++cnt]=v[j],id[cnt]=i;s[++cnt]=cut++;
        }
        Suffix_Array(cnt,s,sa,rk);
        Get_Height(cnt,s,sa,rk,height);
        r--;
        while (l<=r) {
            int mid=l+r>>1;
            if (Check(mid)) l=mid+1; else r=mid-1;
        }
        printf("%d",l);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    函数参数的讨论
    redirect-windows-cmd-stdout-and-stderr-to-a-single-file
    rust 多文件工程
    rust: 默认初始化,函数重载
    VSCode如何格式化所有文件
    FLV协议5分钟入门浅析
    WebRTC:数据传输相关协议简介
    WebSocket协议:5分钟从入门到精通
    Nodejs进阶:crypto模块中你需要掌握的安全基础知识
    前端进阶之路:如何高质量完成产品需求开发
  • 原文地址:https://www.cnblogs.com/mastervan/p/14622499.html
Copyright © 2011-2022 走看看