神妙的战法!
先介绍Shift-And
Task:在s中里找t
做法
遍历s
,采访到s
的第i
位的时候,用bitset
记录t
中哪些前缀,是s.substr(1,i)
的后缀。
如果在这个bitset
中第j
位为1
那么:
s[i]
=t[j]
- 第
j-1
位,在采访到s
的第i-1
位的时候,为1
由此,我们推导出从i-1
到i
位,bitset
的转移。
for(int i=0;t[i];i++)
B[t[i]].set(i);
for(int i=0;s[i];i++) {
D=D<<1, D.set(0);
D &= B[s[i]];
//然后就可以为所欲为
}
再来介绍ShiftOr
在ShiftAnd中。
转移式为D=(D<<1|1)&B[s[i]]
,在这里我们将D取反(1代表不在,0代表在)
转移式为D=(D<<1)|B[s[i]]
来看个栗子:HDU5972
Task:匹配,模板串一个位置有多个选择。
shift-or版本
#include <iostream>
#include <bitset>
#include <vector>
#include <cstring>
using namespace std;
const int N = 1002;
vector<int> v[N];
char s[5000000+10];
int n;
void shift_Or() {
bitset<N> B[10],D;
for(int i=0;i<10;i++) B[i].set();
D.set();
for(int i=0;i<n;i++) {
for(int j=0;j<v[i].size();j++)
B[v[i][j]].reset(i);
}
int len = strlen(s);
for(int i=0;i<len;i++) {
D = D<<1;
D |= B[s[i]-'0'];
if (D[n-1]==0) {
char tmp = s[i+1];
s[i+1]=' ';
puts(s+i-n+1);
s[i+1]=tmp;
}
}
}
int main() {
while (~scanf("%d", &n)) {
for(int i=0;i<n;i++) {
v[i].clear();
int x; scanf("%d", &x);
for(int j=1;j<=x;j++) {
int y; scanf("%d", &y);
v[i].push_back(y);
}
}
scanf("%s", s);
shift_Or();
}
}