51nod——2504 是子序列的个数(一看就会的序列自动机原理)
还以为序列自动机是什么,写完无意间看到帖子原来这就是序列自动机……这算自己发现算法🐎(雾
看网上的序列自动机是O(26*len)预处理,O(len)查询,不过用vector和二分查找就可以更快一点了,写起来也比较清楚。
主要思想就是对于母串,从前往后扫一遍,记录每种(就那26种)字母出现的下标,push_back进vector,这样他们的下标必然升序,也因此可用二分查找去找下标。然后对于子串,也扫一遍,查找子串的每个字母在母串中出现的位置,如果靠后的字母在母串中出现的下标也靠后并且合法,就继续,直到扫完,此串√。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define inf 0x3f3f3f3f 4 vector<int> id[27]; 5 void init(string s){ 6 int len1=s.length(); 7 for(int i=0;i<len1;i++) id[s[i]-'a'].push_back(i); 8 for(int i=0;i<27;i++) id[i].push_back(inf);//方便判是否到串尾 9 } 10 11 bool searchh(string x){//下一个字母出现的合法位置是cur~串尾 12 int a=x[0]-'a'; 13 int cur=id[a][0]; 14 if(cur==inf) return 0; 15 16 cur++; 17 int len2=x.length(); 18 for(int i=1;i<len2;i++){ 19 int t=x[i]-'a'; 20 int tid=*lower_bound(id[t].begin(),id[t].end(),cur); 21 if(tid==inf) return 0; 22 cur=tid+1; 23 } 24 return 1; 25 } 26 int main(){ 27 std::ios::sync_with_stdio(0); 28 cin.tie(0); 29 string s; cin>>s; 30 init(s); 31 int n; cin>>n; 32 int ans=0; 33 for(int i=0;i<n;i++){ 34 string x; cin>>x; 35 if(searchh(x)) ans++; 36 } 37 cout<<ans<<endl; 38 return 0; 39 }
再来个裸题:https://ac.nowcoder.com/acm/contest/392/J
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define inf 0x3f3f3f3f 4 vector<int> id[27]; 5 void init(string s){ 6 int len1=s.length(); 7 for(int i=0;i<len1;i++) id[s[i]-'a'].push_back(i); 8 for(int i=0;i<27;i++) id[i].push_back(inf); 9 } 10 11 bool searchh(string x){ 12 int a=x[0]-'a'; 13 int cur=id[a][0]; 14 if(cur==inf) return 0; 15 16 cur++; 17 int len2=x.length(); 18 for(int i=1;i<len2;i++){ 19 int t=x[i]-'a'; 20 int tid=*lower_bound(id[t].begin(),id[t].end(),cur); 21 if(tid==inf) return 0; 22 cur=tid+1; 23 } 24 return 1; 25 } 26 int main(){ 27 std::ios::sync_with_stdio(0); 28 cin.tie(0); 29 string s; cin>>s; 30 init(s); 31 int n; cin>>n; 32 for(int i=0;i<n;i++){ 33 string x; cin>>x; 34 if(searchh(x)) puts("Yes"); 35 else puts("No"); 36 } 37 return 0; 38 }
Stay Hungry, Stay Foolish