zoukankan      html  css  js  c++  java
  • CF700E:Cool Slogans(SAM,线段树合并)

    Description

    给你一个字符串,如果一个串包含两个可有交集的相同子串,那么这个串的价值就是子串的价值+1。问你给定字符串的最大价值子串的价值。

    Input

    第一行读入字符串长度$n$,第二行是字符串。

    Output

    一行答案。

    Sample Input1

    3
    abc

    Sample Output1

    1

    Sample Input2

    5
    ddddd

    Sample Output2

    5

    Sample Input3

    11
    abracadabra

    Sample Output3

    3

    Solution

    首先把后缀树建立出来,然后从下往上线段树合并一下$endpos$。

    设$f[i]$表示从后缀树的根$DP$到了$i$节点的最大价值,$top[i]$表示$i$节点是从哪个节点转移来的。

    如果父亲代表的字符串在当前节点代表的字符串中出现了两次及以上,那么就$f[x]=f[fa]+1,top[x]=x$

    否则$f[x]=f[fa],top[x]=top[fa]$

    父亲代表的字符串在当前节点代表的字符串中出现的次数可以直接根据$SAM$的$step$数组和线段树合并出的$endpos$什么的直接判断一下。

    Code

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #define N (800009)
      5 using namespace std;
      6 
      7 struct Sgt{int ls,rs,val;}Segt[N<<5];
      8 struct Edge{int to,next;}edge[N<<1];
      9 int n,ans,sgt_num,Root[N],f[N],top[N];
     10 int head[N],num_edge;
     11 int last=1,p,q,np,nq,cnt=1;
     12 int fa[N],son[N][26],step[N],pos[N];
     13 char s[N];
     14 
     15 void add(int u,int v)
     16 {
     17     edge[++num_edge].to=v;
     18     edge[num_edge].next=head[u];
     19     head[u]=num_edge;
     20 }
     21 
     22 void Insert(int x,int r)
     23 {
     24     p=last; np=last=++cnt;
     25     step[np]=step[p]+1; pos[np]=r;
     26     while (p && !son[p][x]) son[p][x]=np, p=fa[p];
     27     if (!p) fa[np]=1;
     28     else
     29     {
     30         q=son[p][x];
     31         if (step[q]==step[p]+1) fa[np]=q;
     32         else
     33         {
     34             nq=++cnt; step[nq]=step[p]+1; pos[nq]=r;
     35             memcpy(son[nq],son[q],sizeof(son[q]));
     36             fa[nq]=fa[q]; fa[q]=fa[np]=nq;
     37             while (son[p][x]==q) son[p][x]=nq, p=fa[p];
     38         }
     39     }
     40 }
     41 
     42 void Update(int &now,int l,int r,int x)
     43 {
     44     if (!now) now=++sgt_num;
     45     Segt[now].val++;
     46     if (l==r) return;
     47     int mid=(l+r)>>1;
     48     if (x<=mid) Update(Segt[now].ls,l,mid,x);
     49     else Update(Segt[now].rs,mid+1,r,x);
     50 }
     51 
     52 int Merge(int x,int y)
     53 {
     54     if (!x || !y) return x|y;
     55     int now=++sgt_num;
     56     Segt[now].ls=Merge(Segt[x].ls,Segt[y].ls);
     57     Segt[now].rs=Merge(Segt[x].rs,Segt[y].rs);
     58     Segt[now].val=Segt[x].val+Segt[y].val;
     59     return now;
     60 }
     61 
     62 int Query(int now,int l,int r,int l1,int r1)
     63 {
     64     if (!now) return 0;
     65     if (l>r1 || r<l1) return 0;
     66     if (l1<=l && r<=r1) return Segt[now].val;
     67     int mid=(l+r)>>1;
     68     return Query(Segt[now].ls,l,mid,l1,r1)+Query(Segt[now].rs,mid+1,r,l1,r1);
     69 }
     70 
     71 void DFS(int x)
     72 {
     73     if (pos[x]) Update(Root[x],1,n,pos[x]);
     74     for (int i=head[x]; i; i=edge[i].next)
     75     {
     76         DFS(edge[i].to);
     77         Root[x]=Merge(Root[x],Root[edge[i].to]);
     78     }
     79 }
     80 
     81 void DP(int x)
     82 {
     83     for (int i=head[x]; i; i=edge[i].next)
     84     {
     85         int y=edge[i].to;
     86         if (x==1) f[y]=1, top[y]=y;
     87         else if (Query(Root[top[x]],1,n,pos[y]-step[y]+step[top[x]],pos[y]-1))
     88             f[y]=f[x]+1, top[y]=y;
     89         else f[y]=f[x], top[y]=top[x];
     90         DP(edge[i].to);
     91         ans=max(ans,f[edge[i].to]);
     92     }
     93 }
     94 
     95 int main()
     96 {
     97     scanf("%d%s",&n,s);
     98     for (int i=0; i<n; ++i) Insert(s[i]-'a',i+1);
     99     for (int i=2; i<=cnt; ++i) add(fa[i],i);
    100     DFS(1); DP(1);
    101     printf("%d
    ",ans);
    102 }
  • 相关阅读:
    nagios监控oracle 表空间
    Oracle报错,ORA-28001: 口令已经失效
    存储基本知识【转载】
    通过shell查找访问日志中访问量最大的ip
    《Java程序设计》 第二周学习任务
    IntelliJ IDEA 激活
    破解某绝地和某DNF辅助
    SMMS:一个不错的免费图床
    Linux使用ASF云挂卡(挂游戏时长)
    Centos7手动编译安装apache
  • 原文地址:https://www.cnblogs.com/refun/p/10295294.html
Copyright © 2011-2022 走看看