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):
The input limits for scoring 70 points are (subproblems G1+G2):
The input limits for scoring 100 points are (subproblems G1+G2+G3):
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; }