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; }