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\n");
66     else dfs(root);
67     return 0;
68 }

 

posted @ 2018-04-02 20:18  CHerish_OI  阅读(170)  评论(0编辑  收藏  举报