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

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 
#include 
#include 
#include 
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 dp[2][3];
bitset 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;
}













你可能感兴趣的:(算法,动态规划,暑假训练+个人复习,2016多校训练,字符串)