HDU5745(2016多校第二场)——La Vie en rose(bitset,动态规划)

本文介绍了一种使用bitset优化模式串匹配的方法,通过构建bitset数组来高效处理字符串匹配问题,特别适用于需要生成大量可能的模式串并查找这些模式串在目标字符串中出现的所有位置的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

La Vie en rose

Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2329    Accepted Submission(s): 706


Problem Description
Professor Zhang would like to solve the multiple pattern matching problem, but he only has only one pattern string p=p1p2...pm. So, he wants to generate as many as possible pattern strings from p using the following method:

1. select some indices i1,i2,...,ik such that 1i1<i2<...<ik<|p| and |ijij+1|>1 for all 1j<k.
2. swap pij and pij+1 for all 1jk.

Now, for a given a string s=s1s2...sn, Professor Zhang wants to find all occurrences of all the generated patterns in s.
 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains two integers n and m (1n105,1mmin{5000,n}) -- the length of s and p.

The second line contains the string s and the third line contains the string p. Both the strings consist of only lowercase English letters.
 

Output
For each test case, output a binary string of length n. The i-th character is "1" if and only if the substring sisi+1...si+m1 is one of the generated patterns.
 

Sample Input
3 4 1 abac a 4 2 aaaa aa 9 3 abcbacacb abc
 

Sample Output
1010 1110 100100100
 


以前都不知道bitset是干嘛用的。

今天学到了,虽然还是半懂不懂的样子。

先贴一些bitset的基本函数(转)

public void set(int pos): 位置pos的字位设置为true。 
public void set(int bitIndex, boolean value) 将指定索引处的位设置为指定的值。 
public void clear(int pos): 位置pos的字位设置为false。
public void clear() : 将此 BitSet 中的所有位设置为 false。 
public int cardinality() 返回此 BitSet 中设置为 true 的位数。 
public boolean get(int pos): 返回位置是pos的字位值。 
public void and(BitSet other): other同该字位集进行与操作,结果作为该字位集的新值。 
public void or(BitSet other): other同该字位集进行或操作,结果作为该字位集的新值。 
public void xor(BitSet other): other同该字位集进行异或操作,结果作为该字位集的新值。
public void andNot(BitSet set) 清除此 BitSet 中所有的位,set - 用来屏蔽此 BitSet 的 BitSet
public int size(): 返回此 BitSet 表示位值时实际使用空间的位数。
public int length() 返回此 BitSet 的“逻辑大小”:BitSet 中最高设置位的索引加 1。 
public int hashCode(): 返回该集合Hash 码, 这个码同集合中的字位值有关。 
public boolean equals(Object other): 如果other中的字位同集合中的字位相同,返回true。 
public Object clone() 克隆此 BitSet,生成一个与之相等的新 BitSet。 
public String toString() 返回此位 set 的字符串表示形式。


其实可以看做一个bool型的数组,但整体的异或移位操作都是常数级别的,所以可以到优化的效果。

至于这道题。

因为dp数组的每一位都代表匹配成功或者不成功,转移关系也是位运算的方式给出。

所以bitset优化很有效。

大部分n*m复杂度暴力搞的现在改了数据好像都会T。。。


代码是从照着题解写的,加了一些注释。

要交G++。。。。

#include <cstdio>
#include <bitset>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100005;
const int M = 5005;
char a[N]; 
char b[M];
//bool dp[N][M][3];    0和前面的交换 1不交换 2和后面的交换
bitset<N> dp[2][3];
bitset<N> w[30];    // 记录对于每个字母 p[i]是否为这个字母
int main()
{
    int T;
    int la, lb;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &la, &lb);
        scanf("%s%s", a, b);

        for (int i = 0; i < 26; ++i) w[i].reset();
        //26个bitset每一个代表的是本字母在模式串里出现的位置
        for (int i = 0; i < la; ++i) w[a[i]-'a'][i] = 1;
        for (int i = 0; i < 2; ++i) for (int j = 0; j < 3; ++j) dp[i][j].reset();
        //这里相当于是对第二位运用到了滚动数组,把模式串作为一个bitset
        dp[0][1] = w[b[0]-'a'];
        if (lb > 1) dp[0][2] = w[b[1]-'a'];

        int now = 0;
        for (int j = 1; j < lb; ++j) {
            now ^= 1;
            //&w[b[j-1]-'a']代表这一位是不是和模式串匹配的
            //如果当前位不交换,相当于是dp[i][j][0]=dp[i-1][j-1][2]&&a[i]==b[j-1]
            //所以<<1一位
            dp[now][0] = ((dp[now^1][2]) << 1) & w[b[j-1]-'a'];
            //dp[i][j][1]=(dp[i-1][j-1][1]||dp[i-1][j-1][0])&&a[i]==b[j-1]
            dp[now][1] = ((dp[now^1][0] | dp[now^1][1]) << 1) & w[b[j]-'a'];
            //dp[i][j][2]=dp[i-1][j-1][1]||dp[i-1][j-1][0]&&a[i]==b[j+1]
            if (j < lb - 1) dp[now][2] = ((dp[now^1][0] | dp[now^1][1]) << 1 ) & w[b[j+1]-'a'];
         }

         for (int i = 0; i < la; ++i) {
             if (dp[now][0][i+lb-1] || dp[now][1][i+lb-1]) printf("1");
             else printf("0");
         }
         puts("");

    }
    return 0;
}













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值