两个串
两个串
(match.cpp/c/pas)
题目描述
兔子们在玩两个串的游戏。给定两个字符串
S
S
S 和
T
T
T,兔子们想知道
T
T
T 在
S
S
S 中出现了几次,分别在哪些位置出现。注意
T
T
T 中可能有“
?
?
?”字符,这个字符可以匹配任何字符。
输入格式
两行两个字符串,分别代表
S
S
S 和
T
T
T
输出格式
第一行一个正整数
k
k
k,表示
T
T
T 在
S
S
S 中出现了几次接下来
k
k
k行正整数,分别代表
T
T
T每次在
S
S
S中出现的开始位置。按照从小到大的顺序输出,
S
S
S 下标从
0
0
0 开始。
样例输入
ababcadaca
a?a
样例输出
3
0
5
7
数据范围与约定
对于 10% 的数据,
S
S
S 和
T
T
T 的长度不超过
100
100
100
对于另外 20% 的数据,
T
T
T 中无“
?
?
?”
对于 100% 的数据,
S
S
S 长度不超过
1
0
5
10^5
105,
T
T
T 长度不会超过
S
S
S。
S
S
S 中只包含小写字母,
T
T
T 中
只包含小写字母和“
?
?
?”
思路:
正解
f
f
t
fft
fft一通乱搞 (可惜我不会) …
然而能用
b
i
t
s
e
t
bitset
bitset艹过去。
先将
S
S
S中每个字母的出现位置标记出来。然后对于
T
T
T中的每一个字母,把
S
S
S的对应位置右移,与之对齐,和
a
n
s
ans
ans做与运算。对于
?
?
?直接跳过。最后
[
1
,
n
−
m
+
1
]
[1,n-m+1]
[1,n−m+1]中
a
n
s
ans
ans为
1
1
1的部分即为匹配上的起点。
时间复杂度:
O
(
n
∗
m
w
(
64
或
32
)
)
O(\frac{n*m}{w(64或32)})
O(w(64或32)n∗m)
代码:
#include<bits/stdc++.h>
using namespace std;
#define in Read()
inline char ch(){
static char buf[1<<21],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}
inline int in{
int s=0,f=1;char x;
for(x=getchar();x<'0'||x>'9';x=getchar()) if(x=='-') f=-1;
for( ;x>='0'&&x<='9';x=getchar()) s=(s<<1)+(s<<3)+(x&15);
return f==1?s:-s;
}
const int A=1e6+5;
char a[A],b[A];
int n,m;
bitset <A> p[30];
signed main(){
scanf("%s%s",a+1,b+1);
n=strlen(a+1),m=strlen(b+1);
for(int i=1;i<=n;i++)
p[a[i]-'a'].set(i);
bitset <A> ans;ans.set();
for(int i=1;i<=m;i++)
if(b[i]!='?') ans&=(p[b[i]-'a']>>(i-1));
int num=0;
for(int i=1;i<=n-m+1;i++) if(ans[i]) num++;
printf("%d\n",num);
for(int i=1;i<=n-m+1;i++)
if(ans[i]) printf("%d\n",i-1);
return 0;
}