dtoj3433. 优美的字符串(str)
dtoj3433. 优美的字符串(str)
`Ivy` 是一个爱美的妹子,所以她喜欢的东西一定是优美的。
在 `Ivy` 眼里,若干小写字母按照某种特定的顺序排列之后形成的序列是较为优美的,她将其定义为「字符串」。`Ivy` 有 n 个字符串,每天,她会选择一个喜欢的作为自己的配饰。
突然有一天,`Ivy` 发现,某一个字符串可能是另外一个字符串的子串。她认为,如果字符串 $a$ 是字符串 $b$ 的子串,那么 $a$ 就是极其优美的!`Ivy` 被这种美深深震撼。
一年一度的 SDOI 到来了,`Ivy` 当然要盛装出席,所以,她会选择一个最优美的字符串作为自己的配饰。`Ivy` 首先定义了一个优美度参数 $k$,然后某一个字符串 $a$ 的优美度被定义为:字符串 $a$ 有多少个子串(不包括空串)是所有 $n$ 个字符串中至少 $k$ 个字符串的子串(注意包括其本身)。
其中「字符串 $a$ 是字符串 $b$ 的子串」定义为:$a$ 对应了 $b$ 的一段连续的区间,即 $a[1...len(a)]=b[l...r],(1\leq l\leq r\leq len(b))$ 。显然,这个命题成立的充要条件为 $len(a)\leq len(b)$。
现在 `Ivy` 想要考考同样要出席 SDOI 的你,她拥有的每一个字符串的优美度是多少。
时间紧迫,你的任务刻不容缓。
Sol
Sol
考虑建广义后缀自动机。
新加入每一个串时令la=rt。
然后可以预处理每一个节点被多少个不同的串覆盖。
具体做法即对于每一个串的每一位都暴力往上跳,跳到被覆盖了为止。
这样效率似乎时n根号的,但我不会证。
然后我们可以dp出每一个点和它的祖先一共有多少个符合要求的子串。
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<string> #define maxn 400005 #define ll long long using namespace std; int n,m,rt=1,la=1,cnt=1; int tax[maxn],ord[maxn]; ll f[maxn]; char ch[maxn];string a[maxn]; struct node{ int Max,par,nex[26]; int now,num; }s[maxn*2]; void ins(int c){ int np=++cnt,p=la;la=np; s[np].Max=s[p].Max+1; for(;p&&!s[p].nex[c];p=s[p].par)s[p].nex[c]=np; if(!p)s[np].par=rt; else { int q=s[p].nex[c]; if(s[q].Max==s[p].Max+1)s[np].par=q; else { int nq=++cnt; s[nq].Max=s[p].Max+1; for(int i=0;i<26;i++)s[nq].nex[i]=s[q].nex[i]; s[nq].par=s[q].par; s[q].par=s[np].par=nq; for(;s[p].nex[c]==q;p=s[p].par)s[p].nex[c]=nq; } } } void Sort(){ for(int i=1;i<=cnt;i++)tax[s[i].Max]++; for(int i=1;i<=cnt;i++)tax[i]+=tax[i-1]; for(int i=1;i<=cnt;i++)ord[tax[s[i].Max]--]=i; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ scanf("%s",ch); a[i]=(string)ch;la=rt; for(int j=0;j<a[i].size();j++){ ins(a[i][j]-'a'); } } for(int i=1;i<=n;i++){ int k=rt; for(int j=0;j<a[i].size();j++){ k=s[k].nex[a[i][j]-'a']; int p=k; for(;s[p].now!=i&&p;p=s[p].par)s[p].num++,s[p].now=i; } } Sort(); s[0].Max=0; for(int i=1;i<=cnt;i++){ int k=ord[i]; f[k]=f[s[k].par]+(s[k].num>=m?-s[s[k].par].Max+s[k].Max:0); } for(int i=1;i<=n;i++){ ll ans=0;int k=rt; for(int j=0;j<a[i].size();j++){ k=s[k].nex[a[i][j]-'a']; ans+=f[k]; } printf("%lld\n",ans); } return 0; }