BZOJ4259 残缺的字符串(FFT)
两个串匹配时相匹配的位置位置差是相同的,那么翻转一个串就变成位置和相同,卷积的形式。
考虑如何使用卷积体现两个位置能否匹配。一个暴力的思路是每次只考虑一种字符,将其在一个串中设为1,并在另一个串中将不是该字符且不是通配符的设为1,卷积结果不为0则无法匹配。这样要跑26次1e6的FFT,就算有6s也……事实上这在luogu就可以过了。
当然这是因为luogu的评测机太神了,我们考虑一些更靠谱的方法。考虑用一些奇技淫巧。
定义两个字符串的距离函数为dis(a,b)=Σ(a[i]-b[i])2a[i]b[i]。通配符在字符串中视为0。可以发现这个式子非常妙的将通配和直接匹配都包括进去了,不同位置间不会相互影响,如果dis=0则相同≠0则不同。将这个式子展开,做三次FFT再加起来就可以了。
居然最慢的只跑了半秒……
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 1050000
int n,m,r[N],t;
char s1[N],s2[N];
bool f[N];
double s[N];
const double PI=3.14159265358979324;
const double eps=1E-;
struct complex
{
double x,y;
complex operator +(const complex&a) const
{
return (complex){x+a.x,y+a.y};
}
complex operator -(const complex&a) const
{
return (complex){x-a.x,y-a.y};
}
complex operator *(const complex&a) const
{
return (complex){x*a.x-y*a.y,x*a.y+y*a.x};
}
}a[N],b[N];
void DFT(int n,complex *a,int p)
{
for (int i=;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
for (int i=;i<=n;i<<=)
{
complex wn=(complex){cos(*PI/i),p*sin(*PI/i)};
for (int j=;j<n;j+=i)
{
complex w=(complex){,};
for (int k=j;k<j+(i>>);k++,w=w*wn)
{
complex x=a[k],y=w*a[k+(i>>)];
a[k]=x+y,a[k+(i>>)]=x-y;
}
}
}
}
void mul(int n,complex *a,complex *b)
{
for (int i=;i<n;i++) a[i].y=a[i].x-b[i].x,a[i].x=a[i].x+b[i].x;
DFT(n,a,);
for (int i=;i<n;i++) a[i]=a[i]*a[i];
DFT(n,a,-);
for (int i=;i<n;i++) a[i].x=a[i].x/n/;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4259.in","r",stdin);
freopen("bzoj4259.out","w",stdout);
const char LL[]="%I64d";
#else
const char LL[]="%lld";
#endif
m=read(),n=read();
scanf("%s%s",s1,s2);
reverse(s1,s1+m);
t=;while (t<=n+m) t<<=;
for (int i=;i<t;i++) r[i]=(r[i>>]>>)|(i&)*(t>>);
for (int i=;i<=n-m+;i++) f[i]=;
for (int i=;i<t;i++) a[i].x=a[i].y=b[i].x=b[i].y=;
for (int i=;i<m;i++) a[i].x=(s1[i]=='*'?:s1[i]-);
for (int i=;i<m;i++) a[i].x=a[i].x*a[i].x*a[i].x;
for (int i=;i<n;i++) b[i].x=(s2[i]=='*'?:s2[i]-);
mul(t,a,b);
for (int i=;i<t;i++) s[i]+=a[i].x;
for (int i=;i<t;i++) a[i].x=a[i].y=b[i].x=b[i].y=;
for (int i=;i<m;i++) a[i].x=(s1[i]=='*'?:s1[i]-);
for (int i=;i<m;i++) a[i].x=a[i].x*a[i].x;
for (int i=;i<n;i++) b[i].x=(s2[i]=='*'?:s2[i]-);
for (int i=;i<n;i++) b[i].x=b[i].x*b[i].x;
mul(t,a,b);
for (int i=;i<t;i++) s[i]-=*a[i].x;
for (int i=;i<t;i++) a[i].x=a[i].y=b[i].x=b[i].y=;
for (int i=;i<m;i++) a[i].x=(s1[i]=='*'?:s1[i]-);
for (int i=;i<n;i++) b[i].x=(s2[i]=='*'?:s2[i]-);
for (int i=;i<n;i++) b[i].x=b[i].x*b[i].x*b[i].x;
mul(t,a,b);
for (int i=;i<t;i++) s[i]+=a[i].x;
for (int i=m-;i<n;i++) if (s[i]>eps) f[i-m+]=;
int cnt=;
for (int i=;i<=n;i++) cnt+=f[i];
cout<<cnt<<endl;
for (int i=;i<=n;i++) if (f[i]) printf("%d ",i);
return ;
}
BZOJ4259 残缺的字符串(FFT)的更多相关文章
- BZOJ4259:残缺的字符串(FFT)
Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同 ...
- BZOJ4259: 残缺的字符串(FFT 字符串匹配)
题意 题目链接 Sol 知道FFT能做字符串匹配的话这就是个裸题了吧.. 考虑把B翻转过来,如果\(\sum_{k = 0}^M (B_{i - k} - A_k)^2 * B_{i-k}*A_k = ...
- luoguP4173 残缺的字符串 FFT
luoguP4173 残缺的字符串 FFT 链接 luogu 思路 和昨天做的题几乎一样. 匹配等价于(其实我更喜欢fft从0开始) \(\sum\limits_{i=0}^{m-1}(S[i+j]- ...
- Luogu P4173 残缺的字符串-FFT在字符串匹配中的应用
P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C ...
- P4173 残缺的字符串(FFT字符串匹配)
P4173 残缺的字符串(FFT字符串匹配) P4173 解题思路: 经典套路将模式串翻转,将*设为0,设以目标串的x位置匹配结束的匹配函数为\(P(x)=\sum^{m-1}_{i=0}[A(m-1 ...
- 【BZOJ4259】残缺的字符串 FFT
[BZOJ4259]残缺的字符串 Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时, ...
- BZOJ 4259: 残缺的字符串 [FFT]
4259: 残缺的字符串 题意:s,t,星号任意字符,匹配方案数 和上题一样 多乘上一个\(a_{j+i}\)就行了 #include <iostream> #include <cs ...
- CF528D Fuzzy Search 和 BZOJ4259 残缺的字符串
Fuzzy Search 给你文本串 S 和模式串 T,求 S 的每个位置是否能模糊匹配上 T. 这里的模糊匹配指的是把 T 放到 S 相应位置上之后,T 中每个字符所在位置附近 k 个之内的位置上的 ...
- 洛谷 P4173 残缺的字符串 (FFT)
题目链接:P4173 残缺的字符串 题意 给定长度为 \(m\) 的模式串和长度为 \(n\) 的目标串,两个串都带有通配符,求所有匹配的位置. 思路 FFT 带有通配符的字符串匹配问题. 设模式串为 ...
随机推荐
- Apache IOUtils的使用
IOUtils 与 FileUtilsCommons IO 是 apache 的一个开源的工具包,封装了 IO操作的相关类,使用 Commons IO 可以很方便的读写文件 commons.jar 包 ...
- jmeter(十一)JDBC Request之Query Type
工作中遇到这样一个问题: 需要准备10W条测试数据,利用jmeter中的JDBC Request向数据库中批量插入这些数据(只要主键不重复就可以,利用函数助手中的Random将主键的ID末尾五位数随机 ...
- 学习CSS布局 - 没有布局
如果你只想把所有内容都塞进一栏里,那么不用设置任何布局也是OK的. 然而,如果用户把浏览器窗口调整的很大,这时阅读网页会非常难受: 读完每一行之后,你的视觉焦点要从右到左移动一大段距离. 试着调整下浏 ...
- 零基础入门到精通:Python大数据与机器学习之Pandas-数据操作
在这里还是要推荐下我自己建的Python开发学习群:483546416,群里都是学Python开发的,如果你正在学习Python ,小编欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python ...
- 自建mvc5项目里几个类图
AccoutController.cs AccountViewModels.cs IdentityModel.cs
- CF418D Big Problems for Organizers 树的直径、ST表
题目传送门:http://codeforces.com/problemset/problem/418/D 大意:给出一棵有$N$个节点的树,所有树边边权为$1$,给出$M$次询问,每个询问给出$x,y ...
- LinqPad的变量比较功能
LinqPad是一个非常方便的C#工具(有免费版和收费版). 今天发现它的变量比较功能真是方便啊.且看3行代码产生如下结果: 说明:图中两个变量的成员属性值分别用红色和绿色背景标注:图很长,只截取了一 ...
- EZ 2018 06 17 NOIP2018 模拟赛(十九)
这次的题目难得的水,但是由于许多哲学的原因,第二题题意表述很迷. 然后是真的猜题意了搞了. 不过这样都可以涨Rating我也是服了. Upt:链接莫名又消失了 A. 「NOIP2017模拟赛11.03 ...
- 【php增删改查实例】第十九节 - session的使用: 让服务器知道你是谁?
因为HTTP请求是一种无状态的请求,所谓无状态,就是服务器不会记录下你本次请求的信息.http它是基于请求 - 相应模式的一种数据传输协议.就是说,你发送一个请求,我服务器给你一个响应,这件事情就算完 ...
- python3通过gevent.pool限制协程并发数量
协程虽然是轻量级的线程,但到达一定数量后,仍然会造成服务器崩溃出错.最好的方法通过限制协程并发数量来解决此类问题. server代码: #!/usr/bin/env python # -*- codi ...