HDU 5972 Regular Number(字符串shift - and算法)
题目链接 HDU5972
2016 ACM/ICPC 大连区域赛 B题
我们预处理出$b[i][j]$,$b[i][j] = 1$的意义是数字$i$可以放在第$j$位。
然后就开始这个匹配的过程。
假设字符串第一位下标从$1$开始
我们每一次处理的子串为$s[i-n+1]$,$s[i-n+2]$, $s[i-n+3]$, ..., $s[i]$
$ans[k] = 1$的含义是 $s[i-k+1], s[i-k+2], s[i-k+3], ..., s[i]$这k位可以与$t[1], t[2], t[3], t[4],..., t[k]$匹配
所以当$ans[n] = 1$的时候我们就可以输出当前这个子串
其中$t[]$表示输入的那张表。
每次处理的时候,我们先把$ans$往右移动一位,然后把$ans[1]$设成$1$.
但是这样是不够的,这相当于把原来那个子串的最前面那位去掉了,我们还要加入最高位。
所以这个时候的$ans$还要和$b[num]$进行与运算。($num$为新的最高位)
于是这样一位位处理过去就可以了。
用bitset优化,输出的时候用字符串输出,不然会超时。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 5000010; const int M = 1002; bitset <M> b[11]; int n; char s[N]; int main(){ while (~scanf("%d", &n)){ rep(i, 0, 9) b[i].reset(); rep(i, 0, n - 1){ int x; scanf("%d", &x); rep(j, 1, x){ int y; scanf("%d", &y); b[y][i] = 1; } } scanf("%s", s); bitset <M> ans; for (int i = 0; s[i]; ++i){ ans <<= 1; ans[0] = 1; ans &= b[s[i] - '0']; if (ans[n - 1]){ char tmp = s[i + 1]; s[i + 1] = '\0'; puts(s + i - n + 1); s[i + 1] = tmp; } } } return 0; }