20200209 SCOI模拟T2(fft/bitset)

两个串

两个串
(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,nm+1] a n s ans ans 1 1 1的部分即为匹配上的起点。
时间复杂度: O ( n ∗ m w ( 64 或 32 ) ) O(\frac{n*m}{w(64或32)}) O(w(6432)nm)

代码:

#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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值