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
1. select some indices i1,i2,...,ik such that 1≤i1<i2<...<ik<|p| and |ij−ij+1|>1 for all 1≤j<k .
2. swap pij and pij+1 for all 1≤j≤k .
Now, for a given a string s=s1s2...sn , Professor Zhang wants to find all occurrences of all the generated patterns in s .
The first line contains two integers n and m (1≤n≤105,1≤m≤min{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.
3 4 1 abac a 4 2 aaaa aa 9 3 abcbacacb abc
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;
}