文章目录
Shift-And/Shift-Or
Shift-And
b i t s e t bitset bitset 初始长度为文本串长度, p o s pos pos 初始化为各个字符出现的位置( b i t s e t bitset bitset 中位置关系是倒置的,0 在最后面)。
a n s = ( a n s < < 1 ∣ 1 ) & p o s [ s [ i ] ] ans=(ans<<1\mid1)\ \&\ pos[s[i]] ans=(ans<<1∣1) & pos[s[i]] , s [ i ] s[i] s[i] 表示对应位置字符。
最后判断 a n s [ n − 1 ] ans[n-1] ans[n−1] 即可知道答案。
// hdu 5972
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
typedef long long LL;
using PII = pair<int, int>;
const int maxn = 5e6 + 5;
const int mod = 1e9 + 7;
bitset<5> pos[10], ans;
char s[maxn];
int main(){
IOS;
int n, k, v;
while(cin >> n){
for(int i = 0; i <= 9; i++) pos[i].reset();
for(int i = 0; i < n; i++){
cin >> k;
while(k--){
cin >> v;
pos[v].set(i);
}
}
cin >> s;
ans.reset();
for(int i = 0; s[i]; i++){
ans <<= 1;
ans |= 1; // ans.set(0);
ans &= pos[s[i] - '0'];
cout << s[i] << " " << ans << endl;
if(ans[n - 1]){
char now = s[i + 1];
s[i + 1] = '\0';
cout << (s + i - n + 1) << endl;
s[i + 1] = now;
}
}
}
}
Shift-Or
b i t s e t bitset bitset 初始长度为文本串长度, p o s pos pos 初始化为各个字符出现的位置。(和 S h i f t − A n d Shift-And Shift−And 不同,0 表示出现,1 表示未出现)
a n s = ( a n s < < 1 ) ∣ p o s [ s [ i ] ] ans=(ans<<1)\mid pos[s[i]] ans=(ans<<1)∣pos[s[i]] , s [ i ] s[i] s[i] 表示对应位置字符。
最后判断 ! a n s [ n − 1 ] !ans[n-1] !ans[n−1] 即可知道答案。比 S h i f t − A n d Shift-And Shift−And 少了一步操作,效率略有提升。
// hdu 5972
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
typedef long long LL;
using PII = pair<int, int>;
const int maxn = 5e6 + 5;
const int mod = 1e9 + 7;
bitset<1005> pos[10], ans;
char s[maxn];
int main(){
IOS;
int n, k, v;
while(cin >> n){
for(int i = 0; i <= 9; i++) pos[i].set();
for(int i = 0; i < n; i++){
cin >> k;
while(k--){
cin >> v;
pos[v].reset(i);
}
}
cin >> s;
ans.set();
for(int i = 0; s[i]; i++){
ans <<= 1;
ans |= pos[s[i] - '0'];
if(!ans[n - 1]){
char now = s[i + 1];
s[i + 1] = '\0';
cout << (s + i - n + 1) << endl;
s[i + 1] = now;
}
}
}
}
KMP
n e x t [ i ] next[i] next[i] 表示 S S S 子串 S [ 0 , i ] S[0,i] S[0,i] 的真后缀与真前缀的最大公共前缀长度,同时也是该位置失配后跳转的位置。
n e x t [ i ] next[i] next[i] 表示长度为 i i i 的前缀的最长 b o r d e r border border 长度
匹配过程中, S S S 串一直在往后移动
S S S 串 A B A ABA ABA, T T T 串 A B A B A ABABA ABABA,匹配过程如下:
A B A B A ABABA ABABA
A B A ABA ABA
A B A B A ABABA ABABA
A B A \ \ \ \ \ \ ABA ABA
//打印 s2 串在 s1 串的位置 洛谷 P3375
#include <bits/stdc++.h>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 5;
char s1[maxn], s2[maxn];
int nxt[maxn], len1, len2;
inline void getnext(){
nxt[0] = nxt[1] = 0;
for(int i = 1, j; i < len2; i++){
j = nxt[i];
while(j && s2[i] != s2[j]) j = nxt[j];
nxt[i + 1] = (s2[i] == s2[j] ? j + 1 : 0);
}
}
int main(){
IOS;
cin >> s1 >> s2;
len1 = strlen(s1), len2 = strlen(s2);
getnext();
for(int i = 0, j = 0; i < len1; i++){
while(j && s1[i] != s2[j]) j = nxt[j];
if(s1[i] == s2[j]) j++;
if(j == len2){
cout << i - len2 + 2 << endl;
j = nxt[j];
}
}
for(int i = 1; i <= len2; i++) cout << nxt[i] << " ";
}
扩展KMP
e x [ i ] ex[i] ex[i] 数组表示字符串的后缀 S [ i , n − 1 ] S[i,n-1] S[i,n−1] 和字符串 s s s 的最大公共前缀长度,将要查询的串和 s s s 串并在一起即可同时求出 e x ex ex 数组。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
typedef long long LL;
const int maxn = 4e7 + 5;
const LL mod = 998244353;
int ex[maxn], slen, tlen;
char s[maxn], t[maxn];
inline void getex(){
int n = slen;
for(int i = 1, l = 0, r = 0; i < n; i++){
ex[i] = i <= r ? min(r - i + 1, ex[i - l]) : 0;
while(i + ex[i] < n && s[ex[i]] == s[i + ex[i]]) ex[i]++;
if(i + ex[i] - 1 > r) l = i, r = i + ex[i] - 1;
}
}
int main(){
IOS;
cin >> t >> s;
slen = strlen(s), tlen = strlen(t);
s[slen] = '|';
ex[0] <