BZOJ-1396/2865: 识别子串

[文章目录]

Description

给定一个字符串S,与一个整数K,定义S的子串T=S(i, j)是关于第K位的识别子串,满足以下两个条件:
1、i≤K≤j。
2、子串T只在S中出现过一次。
例如,S="banana",K=5,则关于第K位的识别子串有"nana","anan","anana","nan","banan"和"banana"。
现在,给定S,XX希望知道对于S的每一位,最短的识别子串长度是多少,请你来帮助他。长度<=5*10^5

就是找end_set大小为1的节点表示最短的子串的长度,即dep[pre]+1。
有了以每个位置结束的最短识别子串的长度其余的都好说。
对于在子串里的点的位数为当前长度,在当前子串前的位置,贡献为其到结束位置的长度,关于位置为一个递降等差序列。
维护的话,分开处理,等差序列那段直接从后向前递推即可,在子串内部的位置用堆以及线段树都是可以的。
1396

#include <queue>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define pb push_back 
#define N 101000 
char s[N];
int n,last=1,tot=1,ch[N<<1][26],pre[N<<1],dep[N<<1],len[N],r[N];
bool vis[N<<1];
void insert(int x)
{
    int p=last,cur=++tot;
    last=cur,dep[cur]=dep[p]+1;
    for(;p&&!ch[p][x];p=pre[p]) ch[p][x]=cur;
    if(!p) pre[cur]=1;
    else
    {
        int q=ch[p][x];
        if(dep[q]==dep[p]+1) pre[cur]=q;
        else
        {
            int clo=++tot;
            memcpy(ch[clo],ch[q],sizeof(ch[q]));
            dep[clo]=dep[p]+1,pre[clo]=pre[q],pre[q]=pre[cur]=clo;
            for(;p&&ch[p][x]==q;p=pre[p]) ch[p][x]=clo;
        }
    }
}
vector<int>ve[N];
priority_queue<int,vector<int>,greater<int> >he,del;
int main()
{
    scanf("%s",s),n=strlen(s);
    int i,j,p;
    for(i=0;i<n;++i) insert(s[i]-'a');
    for(i=1;i<=tot;++i) vis[pre[i]]=1;
    memset(r,0x3f,sizeof(int)*(n+10));
    for(p=1,i=0;i<n;++i) if(!vis[p=ch[p][s[i]-'a']])
        len[i]=dep[pre[p]]+1,r[i-len[i]+1]=min(r[i-len[i]+1],len[i]);
    for(i=n-1;i>=0;--i) r[i]=min(r[i+1]+1,r[i]);
    for(i=0;i<n;++i) if(len[i]) ve[i-len[i]+1].pb(len[i]),ve[i+1].pb(-len[i]);
    for(i=0;i<n;++i)
    {
        for(j=0;j<(int)ve[i].size();++j)
        {
            if(ve[i][j]>0) he.push(ve[i][j]);
            else del.push(-ve[i][j]);
        }
        while(!he.empty()&&!del.empty()&&he.top()==del.top()) he.pop(),del.pop();
        if(he.empty()) printf("%d\n",r[i]);
        else printf("%d\n",min(r[i],he.top()));
    }
    return 0;
}

2865

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define pb push_back 
#define N 501000 
char s[N];
int n,M,last=1,tot=1,ch[N<<1][26],pre[N<<1],dep[N<<1],len[N],r[N],mi[N<<2];
bool vis[N<<1];
void insert(int x)
{
    int p=last,cur=++tot;
    last=cur,dep[cur]=dep[p]+1;
    for(;p&&!ch[p][x];p=pre[p]) ch[p][x]=cur;
    if(!p) pre[cur]=1;
    else
    {
        int q=ch[p][x];
        if(dep[q]==dep[p]+1) pre[cur]=q;
        else
        {
            int clo=++tot;
            memcpy(ch[clo],ch[q],sizeof(ch[q]));
            dep[clo]=dep[p]+1,pre[clo]=pre[q],pre[q]=pre[cur]=clo;
            for(;p&&ch[p][x]==q;p=pre[p]) ch[p][x]=clo;
        }
    }
}
void fix(int l,int r,int w)
{
    l++,r++;
    for(l=l+M-1,r=r+M+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) mi[l^1]=min(mi[l^1],w);
        if(r&1) mi[r^1]=min(mi[r^1],w);
    }
}
int query(int x)
{
    int re=0x3f3f3f3f; x=x+M+1;
    while(x) re=min(re,mi[x]),x>>=1;
    return re;
}
int main()
{
    scanf("%s",s),n=strlen(s);
    int i,p;
    for(i=0;i<n;++i) insert(s[i]-'a');
    for(i=1;i<=tot;++i) vis[pre[i]]=1;
    memset(r,0x3f,sizeof(int)*(n+10));
    for(p=1,i=0;i<n;++i) if(!vis[p=ch[p][s[i]-'a']])
        len[i]=dep[pre[p]]+1,r[i-len[i]+1]=min(r[i-len[i]+1],len[i]);
    for(i=n-1;i>=0;--i) r[i]=min(r[i+1]+1,r[i]);
    for(M=1;M<=(n+1);M<<=1);
    memset(mi,0x3f,sizeof(int)*((M<<1)+10));
    for(i=0;i<n;++i) if(len[i]) fix(i-len[i]+1,i,len[i]);
    for(i=0;i<n;++i) printf("%d\n",min(r[i],query(i)));
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注