https://codeforces.com/problemset/problem/963/D
length distnct
number <= sqrt(1e5)=316
所有串t出现次数<=1e5*315
对于某个串t出现的位置 递增
ac自动机一个点唯一指向另外一个点
记录需要合并的子孙下标,该节点已有的位置
对于目标点,对数组进行合并。
详见代码
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 using namespace std; 9 #define ll long long 10 #include <vector> 11 12 const double eps=1e-8; 13 const ll inf=1e9; 14 const ll mod=1e9+7; 15 const int maxn=1e5+10; 16 const int maxm=sqrt(100)+10; 17 18 /** 19 all string are distinct 20 **/ 21 22 struct node 23 { 24 int num,ind; 25 node *nex[26],*pre,*fail; 26 }*tr,*be,*pos,*p,*td,*q[maxn]; 27 28 char s[maxn],str[maxn]; 29 int least[maxn],re[maxn]; 30 int head1,tail1,d1,q1[maxn],cnt_least; 31 32 vector<int> hap[maxn],son[maxn],temp,temp1; 33 ///son:记录有用的子孙节点的编号,只有处于目标点时才合并 34 35 void arr_merge(int ind) 36 { 37 temp1.clear(); 38 vector<int>::iterator i=temp.begin(),j=hap[ind].begin(),i_end=temp.end(),j_end=hap[ind].end(); 39 while (i!=i_end && j!=j_end) 40 { 41 if (*i < *j) 42 temp1.push_back(*i),i++; 43 else 44 temp1.push_back(*j),j++; 45 } 46 while (i!=i_end) 47 temp1.push_back(*i),i++; 48 while (j!=j_end) 49 temp1.push_back(*j),j++; 50 temp=temp1; 51 } 52 53 int main() 54 { 55 int n,N,len,i,d,head,tail,ind,num,ii,jj; 56 vector<int>::iterator j; 57 tr=new node(); 58 be=new node(); 59 tr->pre=be; 60 tr->fail=be; 61 be->fail=be; 62 for (i=0;i<26;i++) 63 be->nex[i]=tr; 64 65 scanf("%s",s); 66 scanf("%d",&n); 67 for (N=1;N<=n;N++) 68 { 69 scanf("%d%s",&least[N],str); 70 len=strlen(str); 71 re[N]=strlen(str); 72 pos=tr; 73 for (i=0;i<len;i++) 74 { 75 d=str[i]-97; 76 if (!pos->nex[d]) 77 { 78 p=new node(); 79 pos->nex[d]=p; 80 p->pre=pos; 81 } 82 pos=pos->nex[d]; 83 } 84 pos->num=N; 85 } 86 87 head=0,tail=1; 88 q[1]=tr; 89 while (head<tail) 90 { 91 head++; 92 td=q[head]; 93 for (d=0;d<26;d++) 94 if (td->nex[d]) 95 { 96 pos=td->fail; 97 while (!pos->nex[d]) 98 pos=pos->fail; 99 td->nex[d]->fail=pos->nex[d]; 100 q[++tail]=td->nex[d]; 101 td->nex[d]->ind=tail;/// 102 } 103 } 104 105 len=strlen(s); 106 pos=tr; 107 for (i=0;i<len;i++) 108 { 109 d=s[i]-97; 110 while (!pos->nex[d]) 111 pos=pos->fail; 112 pos=pos->nex[d]; 113 114 hap[pos->ind].push_back(i); 115 } 116 117 for (i=tail;i>=1;i--) 118 { 119 pos=q[i]; 120 ind=pos->ind; 121 num=pos->num; 122 if (num) 123 { 124 temp.clear(); 125 head1=0,tail1=1; 126 q1[1]=ind; 127 while (head1<tail1) 128 { 129 head1++; 130 d1=q1[head1]; 131 if (!hap[d1].empty()) 132 { 133 if (temp.empty()) 134 temp=hap[d1]; 135 else 136 arr_merge(d1); 137 } 138 for (j=son[d1].begin();j!=son[d1].end();j++) 139 q1[++tail1]=*j; 140 } 141 hap[ind]=temp; 142 son[ind].clear(); 143 144 cnt_least=inf; 145 // printf("size =%d ",hap[ind].size()); 146 jj=hap[ind].size()-least[num]; 147 for (ii=0;ii<=jj;ii++) 148 cnt_least=min(cnt_least,hap[ind][ii+least[num]-1]-hap[ind][ii]); 149 if (cnt_least==inf) 150 re[num]=-1; 151 else 152 re[num]+=cnt_least; 153 } 154 if (!hap[ind].empty() || !son[ind].empty()) 155 son[pos->fail->ind].push_back(ind); 156 } 157 158 for (i=1;i<=n;i++) 159 printf("%d ",re[i]); 160 return 0; 161 }
bitset方法
https://codeforces.com/contest/963/submission/37784765
代码中
记录文本串s某个字符的所有位置
在模式串中对于一个字符t[i],b[t[i]-'a']为所有可以对应的位置,左移i个单位;如果对于所有j,tmp某个位置都为1,则tmp该个位置为1,模式串t可以与s+j匹配。
时间复杂度O(length(s)*sum(length(t))