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 <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、付费专栏及课程。

余额充值