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 带有通配符的字符串匹配问题. 设模式串为 ...
随机推荐
- coredns CrashLoopBackOff 报错
1.kubectl logs -f coredns-99b9bb8bd-47mvf -n kube-system .:53 2018/09/22 07:39:37 [INFO] CoreDNS-1.2 ...
- SQL Server-聚焦深入理解死锁以及避免死锁建议(转载)
前言 终于进入死锁系列,前面也提到过我一直对隔离级别和死锁以及如何避免死锁等问题模棱两可,所以才鼓起了重新学习SQL Server系列的勇气,本节我们来讲讲SQL Server中的死锁,看到许多文章都 ...
- NoSql的三大基石:CAP理论&BASE&最终一致性
关系型数据库的局限 NoSql出现在关系型数据库之后,主要是为了解决关系型数据库的短板,我们先来看看随着软件行业的发展,关系型数据库面临了哪些挑战: 1.高并发 一个最典型的就是电商网站,例如双11, ...
- 一个有趣的问题——HTTP是“超文本传输协议”还是“超文本转移协议”
最近在看<HTTP图解>这本书,书中提到了对国内对HTTP协议名称的翻译问题,并且给出了一些网友讨论的原稿链接,我看了一下觉得挺有意思的,另外我本人也觉得翻译对于理解协议本身非常重要,就整 ...
- 2.RapidIO串行物理层的包与控制符号
转自https://www.cnblogs.com/liujinggang/p/9932150.html 一.RapidIO串行物理层背景介绍 上篇博文提到RapidIO的物理层支持串行物理层与并行物 ...
- DevOps知识地图实践指南
DevOps知识地图 DevOps方法论的主要来源是Agile, Lean 和TOC, 独创的方法论是持续交付. DevOps经典图书: * <DevOps实践指南> * <持续 ...
- 总结几个常用的系统安全设置(含DenyHosts)
1)禁止系统响应任何从外部/内部来的ping请求攻击者一般首先通过ping命令检测此主机或者IP是否处于活动状态如果能够ping通 某个主机或者IP,那么攻击者就认为此系统处于活动状态,继而进行攻击或 ...
- nginx域名访问的白名单配置梳理
在日常运维工作中,会碰到这样的需求:设置网站访问只对某些ip开放,其他ip的客户端都不能访问.可以通过下面四种方法来达到这种效果:1)针对nginx域名配置所启用的端口(比如80端口)在iptable ...
- hive基础操作—(1)
执行./hive命令后,进入CLI(shell)模式: 1.创建数据库,语句: create database school; 2.展示所有的数据库,语句: show databases; 3.选择使 ...
- Jmeter-使用Stepping Thread Group插件来设置负载场景
前言: 什么是实际的性能测试???1)思考时间:用户在做不同操作之间有时间停顿,或者延迟,思考时间就是模拟用户的操作过程中的停顿的间.2)步伐,速度:主要包括,大量用户进来的时间和退出时间,控制迭代之 ...