题目传送门
题解:
由于k很小,显然要在这里搞一搞事情的。考虑SAM(由于要考虑所有的子串……就直接想SAM了……),由于每个节点保存的是一些后缀,而这个k是对前缀的限制,诶……经典套路了,把输入串反过来,k就变成了对后缀的限制,那么对于每个节点保存的这些后缀,长度小于k的暴力处理,长度大于k的O(1)处理,细节巨多……写了好久。据说SA可以秒。。。
Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
string s[1005];
vector<int> has[1005];
int bas[maxn];
int n,k,L,R;
const int mod = 1e9+7;
typedef pair<int,int> PII;
void do_hash(int x){
has[x].resize(s[x].size()+1);
has[x][s[x].size()]=0;
for (int i=s[x].size()-1;i>=0;i--){
has[x][i] = (26LL*has[x][i+1]+s[x][i]-'a')%mod;
}
}
int get_hash(int x,int l,int r){
return (1LL*has[x][l]-1LL*has[x][r+1]*bas[r-l+1]%mod+mod)%mod;
}
/*注意需要按l将节点基数排序来拓扑更新parent树*/
struct Suffix_Automaton{
//basic
int nxt[maxn*2][26],fa[maxn*2],l[maxn*2];
PII pos[maxn*2];
int last,cnt;
void clear(){
last =cnt=1;
fa[1]=l[1]=0;
memset(nxt[1],0,sizeof nxt[1]);
}
void init(string s,int posI){
for (int i=0;i<s.size();i++){
int c = s[i]-'a';
int p = last;
int np = ++cnt;
l[np] = l[p]+1;
pos[np] = {posI,i};
last = np;
while (p&&!nxt[p][c])nxt[p][c] = np,p = fa[p];
if (!p)fa[np]=1;
else{
int q = nxt[p][c];
if (l[q]==l[p]+1)fa[np] =q;
else{
int nq = ++ cnt;
l[nq] = l[p]+1;
pos[nq] ={posI,i};
memcpy(nxt[nq],nxt[q],sizeof (nxt[q]));
fa[nq] =fa[q];
fa[np] = fa[q] =nq;
while (nxt[p][c]==q)nxt[p][c] =nq,p = fa[p];
}
}
}
}
int calc(int L,int R,int l,int r){
if(r<L||R<l)return 0;
if(l>=L&&l<=R)return min(r,R)-l+1;
else return min(r,R)-L+1;
}
long long query(){
long long ret =0;
for (int i=2;i<=cnt;i++){
int len = min(l[fa[i]],k);
int V = get_hash(pos[i].first,pos[i].second-len+1,pos[i].second);
if(l[fa[i]]<=k){
for (int j=l[fa[i]]+1;j<=min(k,l[i]);j++){
V = (26LL*V+s[pos[i].first][pos[i].second+1-j]-'a')%mod;
if(V>=L&&V<=R)ret++;
}
if(l[i]>k){
int len = l[i]-k;
V++;V%=mod;
int VV = V+len-1;
if(VV>=mod){
ret+=calc(L,R,0,VV-mod);
ret+=calc(L,R,V,mod-1);
}else{
ret+=calc(L,R,V,VV);
}
}
}else{
V +=(l[fa[i]]-k);
V++;V%=mod;
int VV = V+l[i]-l[fa[i]]-1;
if(VV>=mod){
ret+=calc(L,R,0,VV-mod);
ret+=calc(L,R,V,mod-1);
}else{
ret+=calc(L,R,V,VV);
}
}
}
return ret;
}
}sam;
int main(){
#ifdef ONLINE_JUDGE
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
#endif
bas[0]=1;
for (int i=1;i<maxn;i++){
bas[i] = 26LL*bas[i-1]%mod;
}
cin>>n>>k>>L>>R;
sam.clear();
for (int i=0;i<n;i++){
cin>>s[i];
reverse(s[i].begin(),s[i].end());
do_hash(i);
sam.last=1;
sam.init(s[i],i);
}
cout<<sam.query()<<'\n';
return 0;
}