码迷,mamicode.com
首页 > 其他好文 > 详细

[Luogu2463][SDOI2008]Sandy的卡片

时间:2018-02-24 23:05:00      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:连续   ring   ace   二分   new   name   bzoj   存在   sdoi2008   

BZOJ权限题qwq
Luogu

sol

“两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串”
其实就是差分一波以后完全相同
所以对输入的数据进行差分,同时记一下每一个位置是属于哪个串的。
记得在串与串中间加入一个没有出现的字符。
求出SA后二分答案\(mid\),问题变成:\(Height\)数组里是否存在一个大于等于\(mid\)的连续段使每个串都在里面出现过。
开桶记录。记一个\(id\)避免每次对桶的清空。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 1e6+1e4+5;
int n,tot,a[N],b[N],t[N],x[N],y[N],SA[N],Rank[N],Height[N],id;
bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
void getSA()
{
    int m=1e6+1e4;
    for (int i=1;i<=n;++i) ++t[x[i]=a[i]];
    for (int i=1;i<=m;++i) t[i]+=t[i-1];
    for (int i=n;i>=1;--i) SA[t[x[i]]--]=i;
    for (int k=1;k<=n;k<<=1)
    {
        int p=0;
        for (int i=0;i<=m;++i) y[i]=0;
        for (int i=n-k+1;i<=n;++i) y[++p]=i;
        for (int i=1;i<=n;++i) if (SA[i]>k) y[++p]=SA[i]-k;
        for (int i=0;i<=m;++i) t[i]=0;
        for (int i=1;i<=n;++i) ++t[x[y[i]]];
        for (int i=1;i<=m;++i) t[i]+=t[i-1];
        for (int i=n;i>=1;--i) SA[t[x[y[i]]]--]=y[i];
        swap(x,y);
        x[SA[1]]=p=1;
        for (int i=2;i<=n;++i) x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
        if (p>=n) break;
        m=p;
    }
    for (int i=1;i<=n;++i) Rank[SA[i]]=i;
    for (int i=1,j=0;i<=n;++i)
    {
        if (j) --j;
        while (a[i+j]==a[SA[Rank[i]-1]+j]) ++j;
        Height[Rank[i]]=j;
    }
}
bool check(int mid)
{
    ++id;int cnt=0;
    for (int i=1;i<=n;++i)
        if (Height[i]>=mid)
        {
            if (t[b[SA[i-1]]]!=id) t[b[SA[i-1]]]=id,++cnt;
            if (t[b[SA[i]]]!=id) t[b[SA[i]]]=id,++cnt;
            if (cnt==tot) return true;
        }
        else cnt=0,++id;
    return false;
}
int main()
{
    tot=gi();
    for (int i=1;i<=tot;++i)
    {
        for (int j=1,len=gi();j<=len;++j)
            t[j]=gi(),a[++n]=t[j]-t[j-1]+5e5,b[n]=i;
        a[++n]=1e6+i;
    }
    memset(t,0,sizeof(t));
    getSA();
    memset(t,0,sizeof(t));
    int l=0,r=n;
    while (l<r)
    {
        int mid=l+r+1>>1;
        if (check(mid)) l=mid;
        else r=mid-1;
    }
    printf("%d\n",l+1);
    return 0;
}

[Luogu2463][SDOI2008]Sandy的卡片

标签:连续   ring   ace   二分   new   name   bzoj   存在   sdoi2008   

原文地址:https://www.cnblogs.com/zhoushuyu/p/8467787.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!