题目
Smart Beaver recently got interested in a new word game. The point is as follows: count the number of distinct good substrings of some string s. To determine if a string is good or not the game uses rules. Overall there are n rules. Each rule is described by a group of three (p, l, r), where p is a string and l and r (l ≤ r) are integers. We’ll say that string t complies with rule (p, l, r), if the number of occurrences of string t in string p lies between l and r, inclusive. For example, string "ab", complies with rules ("ab", 1, 2) and ("aab", 0, 1), but does not comply with rules ("cd", 1, 2) and ("abab", 0, 1).
A substring s[l... r] (1 ≤ l ≤ r ≤ |s|) of string s = s1s2... s|s| (|s| is a length of s) is string slsl + 1... sr.
Consider a number of occurrences of string t in string p as a number of pairs of integers l, r (1 ≤ l ≤ r ≤ |p|) such that p[l... r] = t.
We’ll say that string t is good if it complies with all n rules. Smart Beaver asks you to help him to write a program that can calculate the number of distinct good substrings of string s. Two substrings s[x... y] and s[z... w] are cosidered to be distinct iff s[x... y] ≠ s[z... w].
The first line contains string s. The second line contains integer n. Next n lines contain the rules, one per line. Each of these lines contains a string and two integers pi, li, ri, separated by single spaces (0 ≤ li ≤ ri ≤ |pi|). It is guaranteed that all the given strings are non-empty and only contain lowercase English letters.
The input limits for scoring 30 points are (subproblem G1):
- 0 ≤ n ≤ 10.
- The length of string s and the maximum length of string p is ≤ 200.
The input limits for scoring 70 points are (subproblems G1+G2):
- 0 ≤ n ≤ 10.
- The length of string s and the maximum length of string p is ≤ 2000.
The input limits for scoring 100 points are (subproblems G1+G2+G3):
- 0 ≤ n ≤ 10.
- The length of string s and the maximum length of string p is ≤ 50000.
Print a single integer — the number of good substrings of string s.
题解
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define Nil NULL
typedef long long LL;
const int INF=0x7ffffff/2;
const int SIZEP=50010;
const int LNUM=11;
int M;//限制的数量
int lim_l[LNUM],lim_r[LNUM];
int match[256]={0};
class Suffix_Automaton{
public:
class Node{
public:
int len;
Node *suflink;//后缀链接
Node *ch[26+LNUM];//转移
int sz[LNUM];//在每个模式串中出现次数
bool good;//是否对应"好"字符串
int range;//对应多少个字符串
int last;//首次出现位置
LL suf_sz;//后缀链接能到达好节点的range之和
void calc_range(void){
range=len;
if(suflink!=Nil) range-=suflink->len;
}
void calc_good(void){
for(int i=1;i<=M;i++){
if(!(lim_l[i]<=sz[i]&&sz[i]<=lim_r[i])){
good=false;
return;
}
}
good=true;
}
void clear(void){
len=0;
suflink=Nil;
memset(ch,0,sizeof(ch));
memset(sz,0,sizeof(sz));
good=false;
range=0;
last=-1;
suf_sz=0;
}
Node(){clear();}
};
Node *root,*last;
int n;
Node *lis[1100050];
int timer;
int findpos(Node *a){
if(a==Nil) return -1;
for(int i=0;i<n;i++){
if(lis[i]==a) return i;
}
return -2;
}
void print(Node *a){
cout<<"addr: "<<findpos(a)<<endl;
cout<<"len: "<<a->len<<endl;
cout<<"suflink: "<<findpos(a->suflink)<<endl;
cout<<"good: "<<a->good<<endl;
cout<<"last: "<<a->last<<endl;
cout<<"suf_sz: "<<a->suf_sz<<endl;
cout<<"sz: ";for(int i=0;i<=M;i++){cout<<a->sz[i]<<" ";}cout<<endl;
for(int i=0;i<26+LNUM;i++){if(a->ch[i]!=Nil){cout<<(char)('a'+i)<<" : "<<findpos(a->ch
[i])<<endl;}}
cout<<endl;
}
void clear(void){
root=new Node;
last=root;
lis[0]=root;
n=1;
timer=0;
}
Suffix_Automaton(void){clear();}
void insert(char c,int id){
int k=match[c];
Node *cur=new Node;
if(id!=-1) cur->sz[id]=1;
lis[n++]=cur;
cur->len=last->len+1;
if(id==0) cur->last=timer++;
Node *p=last;
while(p!=Nil&&p->ch[k]==Nil){
p->ch[k]=cur;
p=p->suflink;
}
if(p==Nil) cur->suflink=root;
else{
Node *q=p->ch[k];
if(p->len+1==q->len) cur->suflink=q;
else{
Node *clone=new Node;
lis[n++]=clone;
*clone=*q;
memset(clone->sz,0,sizeof(clone->sz));
clone->len=p->len+1;
cur->suflink=clone;
q->suflink=clone;
while(p!=Nil&&p->ch[k]==q){
p->ch[k]=clone;
p=p->suflink;
}
}
}
last=cur;
}
class cmp_len{
public:
bool operator () (Node *a,Node *b){
return a->len<b->len;
}
};
void prepare(void){
sort(lis,lis+n,cmp_len());
for(int i=n-1;i>=0;i--){
Node *p=lis[i];
if(p->suflink!=Nil){
for(int j=0;j<=M;j++) p->suflink->sz[j]+=p->sz[j];
p->suflink->last=max(p->suflink->last,p->last);
}
}
for(int i=0;i<n;i++) lis[i]->calc_good(),lis[i]->calc_range();
for(int i=0;i<n;i++){
Node *p=lis[i];
if(p->suflink!=Nil&&p->last==p->suflink->last){
Node *q=p->suflink;
p->suf_sz+=q->suf_sz;
if(q->good){
p->suf_sz+=q->range;
}
}
}
}
LL calc(char *s,int L){
LL ans=0;
Node *p=root;
int now=0;
for(int i=0;i<L;i++){
int k=match[s[i]];
while(p!=root&&p->ch[k]==Nil){
p=p->suflink;
now=p->len;
}
if(p->ch[k]!=Nil) p=p->ch[k],now++;
if(p->last==i){//保证不重
ans+=p->suf_sz;
if(p->good){
ans+=now;
if(p->suflink!=Nil) ans-=p->suflink->len;
}
}
}
return ans;
}
};
Suffix_Automaton MT;
char S[SIZEP];
int L;
char str[SIZEP];
void build_MT(void){
memset(match,-1,sizeof(match));
for(int i=0;i<26;i++) match['a'+i]=i;
for(int i=0;i<20;i++) match[i]=26+i;
scanf("%s",S);
scanf("%d",&M);
char dlm='\0';
L=strlen(S);
for(int i=0;i<L;i++){
MT.insert(S[i],0);
}
MT.insert(dlm++,-1);
for(int i=1;i<=M;i++){
scanf("%s",str);
scanf("%d%d",&lim_l[i],&lim_r[i]);
int len=strlen(str);
for(int k=0;k<len;k++){
MT.insert(str[k],i);
}
MT.insert(dlm++,-1);//分隔符
}
}
int main(){
//freopen("t1.in","r",stdin);
build_MT();
MT.prepare();
cout<<MT.calc(S,L)<<endl;
return 0;
}