补题计划
Posted rilisoft
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了补题计划相关的知识,希望对你有一定的参考价值。
[TJOI2015]弦论(sam)
首先建出当前串s的sam。然后分t=1或者0两种情况讨论。
当t=1时,位置不同的相同字符串算不同。
设开头为某一个x对应的字符串的子串个数是$f[x]$,节点x对应的字符串在整个字符串中出现了$s[x]$次。我们可以通过dfs算法在$parent$树上跑算出$f$和$s$。
我们为了查询字典序,需要从起始节点开始跑自动机。设当前节点为x,代表字符串是s,然后由字典序小到大枚举x后面添加的字符c。如果现在以x+c为开头对应的字符串数量比较小,那么把k减去对应的f。否则,x转移到s+c所对应的节点。
注意每次x转移后也要减去$s[x]$。否则由于没有算上x的贡献,会导致答案错误。
#include<bits/stdc++.h> #define mn 1000005 using namespace std; char str[mn];long long ans; int a,k; int fa[mn],t[mn][26],len[mn],la,ct,v[mn],h[mn],nxt[mn],ec,s[mn],f[mn]; void add(int c) int cur=++ct,p=la;len[cur]=len[la]+1;s[cur]=1;la=cur; for(;p&&!t[p][c];p=fa[p])t[p][c]=cur; if(!p)fa[cur]=1; else int q=t[p][c];if(len[p]+1==len[q])fa[cur]=q; else int cl=++ct;len[cl]=len[p]+1;memcpy(t[cl],t[q],sizeof(t[cl])); fa[cl]=fa[q];fa[cur]=fa[q]=cl; for(;t[p][c]==q;p=fa[p])t[p][c]=cl; void init()ct=ec=la=1; void adj(int x,int y)v[++ec]=y;nxt[ec]=h[x];h[x]=ec; void bd()for(int i=2;i<=ct;i++)adj(fa[i],i); int g1(int x) for(int i=h[x];i;i=nxt[i]) s[x]+=g1(v[i]); return s[x]; int g2(int x) if(f[x])return f[x]; if(a)f[x]=s[x]; else f[x]=1; for(int i=0;i<26;i++) if(t[x][i])f[x]+=g2(t[x][i]); return f[x]; int main() freopen("string.in","r",stdin); freopen("string.out","w",stdout); scanf("%s%d%d",str+1,&a,&k);init(); for(int i=1;str[i];i++)add(str[i]-‘a‘); bd();g1(1);g2(1); int x=1; while(k>0) for(int i=0;i<26;i++) int v=t[x][i]; if(k>f[v])k-=f[v]; else x=v; if(!a)k--; else k-=s[v]; printf("%c",i+‘a‘); break;
以上是关于补题计划的主要内容,如果未能解决你的问题,请参考以下文章