zoukankan      html  css  js  c++  java
  • bzoj3998: [TJOI2015]弦论(SAM+dfs)

    3998: [TJOI2015]弦论

    题目:传送门 


    题解:

       SAM的入门题目(很好的复习了SAM并加强Right集合的使用)

       其实对于第K小的字符串直接从root开始一通DFS就好,因为son边是直接根据字符存的呀,相当于自带字典序,直接从‘a' 开始找。

       一开始初始化一下从当前状态出发所能走的路径数(也就是能构成多少个字符串啦)

       然后根据T= 0/1分情况来处理Right集合大小:

       T== 0 :那Right集合大小就直接全部等于1咯

       T== 1  : 直接累加啊(原始操作)

       然后具体看代码注释吧:

        


    代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 struct SAM
     8 {
     9     int son[31],fail,dep;
    10 }ch[1110000];int cnt,last,root,a[510000];
    11 void add(int k)
    12 {
    13     int x=a[k];
    14     int p=last,np=++cnt;ch[np].dep=k;
    15     while(p && ch[p].son[x]==0)ch[p].son[x]=np,p=ch[p].fail;
    16     if(p==0)ch[np].fail=root;
    17     else
    18     {
    19         int q=ch[p].son[x];
    20         if(ch[p].dep+1==ch[q].dep)ch[np].fail=q;
    21         else
    22         {
    23             int nq=++cnt;
    24             ch[nq]=ch[q];ch[nq].dep=ch[p].dep+1;
    25             ch[np].fail=ch[q].fail=nq;
    26             while(p && ch[p].son[x]==q)ch[p].son[x]=nq,p=ch[p].fail;
    27         }
    28     }
    29     last=np;
    30 }
    31 int len,T,k,Rsort[1110000],r[1110000],sa[1110000],sum[1110000];
    32 char s[510000];
    33 void dfs(int x)
    34 {
    35     if(k<=r[x])return ;
    36     k-=r[x];//要从x继续往下搜,那么结束位置为x的子串一定会更优,那就减去这样的子串个数啊,r记录的就是这个 
    37     for(int i=0;i<=25;i++)
    38         if(ch[x].son[i]!=0)
    39         {
    40             int y=ch[x].son[i];
    41             if(k>sum[y])k-=sum[y];//当前k如果比y可以走出来的路径还要多,那么第k小的一定不在y的路径上。由于是按照字典序小到大问的,那么y的路径一定比后面枚举的要优,那也要减,sum记录的就是可行路径数 
    42             else {printf("%c",i+'a');dfs(y);return ;}
    43         }
    44 }
    45 int main()
    46 {
    47     cnt=0;root=last=++cnt;
    48     scanf("%s",s+1);len=strlen(s+1);
    49     for(int i=1;i<=len;i++)a[i]=s[i]-'a';
    50     for(int i=1;i<=len;i++)add(i);
    51     scanf("%d%d",&T,&k);
    52     for(int i=1;i<=cnt;i++)Rsort[ch[i].dep]++;
    53     for(int i=1;i<=len;i++)Rsort[i]+=Rsort[i-1];
    54     for(int i=cnt;i>=1;i--)sa[Rsort[ch[i].dep]--]=i;
    55     for(int i=1,p=root;i<=len;i++)p=ch[p].son[a[i]],r[p]++;
    56     for(int i=cnt;i>=1;i--)
    57         if(T==0)r[ch[sa[i]].fail]=1;
    58         else r[ch[sa[i]].fail]+=r[sa[i]];
    59     r[root]=0;
    60     for(int i=cnt;i>=1;i--)
    61     {
    62         int now=sa[i];sum[now]=r[now];
    63         for(int j=0;j<=25;j++)if(ch[now].son[j]!=0)sum[now]+=sum[ch[now].son[j]];
    64     }
    65     if(k>sum[root])printf("-1
    ");
    66     else dfs(root);
    67     return 0;
    68 }
  • 相关阅读:
    Smobiler如何实现.net一键开发,ios和android跨平台运行
    使用Smobiler实现类似美团的界面
    疫情当下,企业系统如何快速实现移动化?
    Smobiler针对百度文字识别SDK动态编译与运行
    smobiler自适应不同手机分辨率
    仓库管理移动应用解决方案——C#开发的移动应用开源解决方案
    移动OA办公——Smobiler第一个开源应用解决方案,快来get吧
    react-native 标题随页面滚动显示和隐藏
    react-native 键盘遮挡输入框
    解决adb网络连接中出现的“由于目标计算机积极拒绝,无法连接”错误
  • 原文地址:https://www.cnblogs.com/CHerish_OI/p/8696891.html
Copyright © 2011-2022 走看看