字符串板刷
有個規則,每個規則由字符串以及整數對構成。
如果一個字符串在中的出現次數在內,就說明滿足了規則.
如果一個字符串滿足了所有個規則,就說明它是好的。
給定一個字符串,問它的不同好子串數量。
這個問題有分級:的長度在以內,分別對應難度.
對於長度在以內的情況,可以對個串和串都建立後綴自動機。
在遍歷所有路徑(不同子串),將經過的字符分別插入到串的後綴自動機中,即可知道的每個子串在每個串中出現的次數。
對於長度在以內的情況,可以把所有字符串加上分隔符連接起來,然後統計每個節點在所有串中的出現次數,最後計數一遍就好。
困了。
時刻注意,一個節點的貢獻不是1,而是它所表示的字符串數量。
有一個找了好長時間的bug,原來是因爲我的分隔符設定成,然後爆char,然後變成負數之後RE了。
分隔符設置成一樣是可以的,只要將其算入另外的字符串中。
/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 500016, MOD = 1000000007;
int sz, lst; //後綴自動機大小,上一次插入的節點
int ch[M<<1][40], len[M<<1], link[M<<1], cnt[12][M<<1];
void extend(const char *s, int id)
{
for(int i=0; s[i]; ++i)
{
int c = s[i]-'a';
int cur = ++sz;
len[cur] = len[lst] + 1;
int p = lst;
while(!ch[p][c])
{
ch[p][c] = cur;
p = link[p];
}
if(ch[p][c] != cur)
{
int q = ch[p][c];
if(len[p] + 1 == len[q]) link[cur] = q;
else
{
int clone = ++sz;
memcpy(ch[clone], ch[q], sizeof(ch[q]));
link[clone] = link[q];
len[clone] = len[p]+1;
while(ch[p][c]==q)
{
ch[p][c] = clone;
p = link[p];
}
link[q] = link[cur] = clone;
}
}
lst = cur;
++cnt[id][cur];
}
}
void build()
{
vector<int> nodes;
for(int i=1; i<=sz; ++i)
nodes.push_back(i);
sort(nodes.begin(), nodes.end(), [&](int a, int b){
return len[a]>len[b];
});
for(auto u:nodes)
for(auto cntx:cnt)
cntx[link[u]] += cntx[u];
}
char str[M];
int lef[M], rig[M];
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
scanf("%s", str); extend(str, 0);
lef[0] = 1, rig[0] = 50000;
int n = read();
for(int i=1; i<=n; ++i)
{
string t = "{";
extend(t.c_str(), n+1);
scanf("%s", str);
extend(str, i);
lef[i] = read(), rig[i] = read();
}
build();
int ans = 0;
for(int i=1; i<=sz; ++i)
{
int suc = 1;
for(int j=0; j<=n; ++j)
if(cnt[j][i]<lef[j] || cnt[j][i]>rig[j])
suc = 0, j=n+1;
ans += suc*(len[i]-len[link[i]]);
}
printf("%d\n",ans );
return 0;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}