Regular Number HDU - 5972(巧妙的字符串匹配+bitset)

Regular Number HDU - 5972

 Using regular expression to define a numeric string is a very common thing. Generally, use the shape as follows:
(0|9|7) (5|6) (2) (4|5)
Above regular expression matches 4 digits:The first is one of 0,9 and 7. The second is one of 5 and 6. The third is 2. And the fourth is one of 4 and 5. The above regular expression can be successfully matched to 0525, but it cannot be matched to 9634.
Now,giving you a regular expression like the above formula,and a long string of numbers,please find out all the substrings of this long string that can be matched to the regular expression.

Input
It contains a set of test data.The first line is a positive integer N (1 ≤ N ≤ 1000),on behalf of the regular representation of the N bit string.In the next N lines,the first integer of the i-th line is ai(1≤ai≤10),representing that the i-th position of regular expression has ai numbers to be selected.Next there are ai
numeric characters. In the last line,there is a numeric string.The length of the string is not more than 5 * 10^6.
Output
Output all substrings that can be matched by the regular expression. Each substring occupies one line
Sample Input

4
3 0 9 7
2 5 7
2 2 5
2 4 5
09755420524

Sample Output

9755
7554
0524
题意:

给你N位数,接下来有N行,第i行先输入n,表示这个数的第i 位上可以在接下来的n个数中挑选,然后i 行再输n个数。
然后输入需要匹配的母串,让你输出母串中有多少个可行的N位子串。

分析:

这里用到了STL中的bitset,bitset可以就把他当成一个二进制串,二进制串能进行的操作它都能进行,比如左移位右移位之类的,当然了它还有更多的功能

这里我们用到了reset()方法将位数全部设为0,set(i)方法,将第i位设为1(注意类比二进制第i位是从右往左第i位)

具体bitset用法详见bitset - C++ Reference

现在我们来看一下这道题目:

n位数,每行给若干个数,我们可以这样记录,以出现的每个数为下表,用bitset记录每个数都可以出现在第几个位置,可以出现在这里记为1否则为0,需要一个bitset< MAXN > s[ MAX_DIGIT ]
0: 0001001 (代表数字0可以出现在第0个位置和第3个位置)
1: 0000000
2: 0000000
3: 0000000
.
.
.
9: 0000000

然后用另一个bitset,ans,其中要使两个bitset位数相同,这样才能用&来判断,过程如下:
ans 初始00000…0000
我们先将视野具体到1个位上而不管其他位,我们先只看第0位是怎么运作的
为了判断这一位是否能有数可放,使用按位与运算&,所以第0位我们先设为1
这样就是000…0001
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i
只看下标i的移动
我们遍历给定的字符串0~len-1
目前判断第0位,用ans&我们之前存的当前数字的bitset,如果这个数字在这一位也是1,那么i位就还是1,否则变成了0。
现在判断完了第0位,将ans左移1位,这样i到了第1位,字符串也向后遍历一位,这样我们再看这个数字能否在第1位出现
00000…010
//i
00000…101 (假设这是当前数字的bitset)
他们再进行按位与,如果是0就ans中的i位就变成了0,那么我们可以发现以后再往后移动,知道移到n-1位都是0了,换句话说这个位从开始到结束就代表判断一个n位数字,只要前面有一位不匹配了,那么后面都肯定都不匹配了,这就是这个地方的妙处,每次我们判断一下ans[n-1](因为实际从0位开始,长度n就到n-1位)是不是1就知道行不行了,是1说明匹配到了一个n位的子串。

上面我们只解释的一个位1从0位移到n-1位的判断过程,那其他怎么办,很简单,每次左移一位后第0位我们都设为1,这样就像是一个流水线一样,每次都进行同样的操作,每次判断ans[n-1]是不是1就可以了然后输入这一段n位字符串就可以了

具体看代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+50;
char str[5*maxn];
bitset<1005> s[20];
bitset<1005> ans;

int main(){
    int n;
    while(~scanf("%d",&n)){
        for(int i = 0; i < 20; i++){
            s[i].reset();
        }
        ans.reset();
        for(int i = 0; i < n; i++){
            int N,temp;
            scanf("%d",&N);
            for(int j = 0; j < N; j++){
                scanf("%d",&temp);
                s[temp].set(i);
            }
        }
        scanf("%s",str);
        int len = strlen(str);
        for(int i = 0; i < len; i++){
            ans = ans << 1;
            ans[0] = 1;
            ans &= s[str[i]-'0'];
            if(ans[n-1] == 1){
                char temp = str[i+1];
                str[i+1] = '\0';
                printf("%s\n",str+i-n+1);
                str[i+1] = temp;
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值