两个串匹配时相匹配的位置位置差是相同的,那么翻转一个串就变成位置和相同,卷积的形式。

  考虑如何使用卷积体现两个位置能否匹配。一个暴力的思路是每次只考虑一种字符,将其在一个串中设为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)的更多相关文章

  1. BZOJ4259:残缺的字符串(FFT)

    Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同 ...

  2. BZOJ4259: 残缺的字符串(FFT 字符串匹配)

    题意 题目链接 Sol 知道FFT能做字符串匹配的话这就是个裸题了吧.. 考虑把B翻转过来,如果\(\sum_{k = 0}^M (B_{i - k} - A_k)^2 * B_{i-k}*A_k = ...

  3. luoguP4173 残缺的字符串 FFT

    luoguP4173 残缺的字符串 FFT 链接 luogu 思路 和昨天做的题几乎一样. 匹配等价于(其实我更喜欢fft从0开始) \(\sum\limits_{i=0}^{m-1}(S[i+j]- ...

  4. Luogu P4173 残缺的字符串-FFT在字符串匹配中的应用

    P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C ...

  5. P4173 残缺的字符串(FFT字符串匹配)

    P4173 残缺的字符串(FFT字符串匹配) P4173 解题思路: 经典套路将模式串翻转,将*设为0,设以目标串的x位置匹配结束的匹配函数为\(P(x)=\sum^{m-1}_{i=0}[A(m-1 ...

  6. 【BZOJ4259】残缺的字符串 FFT

    [BZOJ4259]残缺的字符串 Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时, ...

  7. BZOJ 4259: 残缺的字符串 [FFT]

    4259: 残缺的字符串 题意:s,t,星号任意字符,匹配方案数 和上题一样 多乘上一个\(a_{j+i}\)就行了 #include <iostream> #include <cs ...

  8. CF528D Fuzzy Search 和 BZOJ4259 残缺的字符串

    Fuzzy Search 给你文本串 S 和模式串 T,求 S 的每个位置是否能模糊匹配上 T. 这里的模糊匹配指的是把 T 放到 S 相应位置上之后,T 中每个字符所在位置附近 k 个之内的位置上的 ...

  9. 洛谷 P4173 残缺的字符串 (FFT)

    题目链接:P4173 残缺的字符串 题意 给定长度为 \(m\) 的模式串和长度为 \(n\) 的目标串,两个串都带有通配符,求所有匹配的位置. 思路 FFT 带有通配符的字符串匹配问题. 设模式串为 ...

随机推荐

  1. apache、nginx的虚拟域名配置和rewrite配置,以及web缓存的几种方式

    web缓存一般用来缓解数据库压力. 通常有几种方法,文件静态化,缓存服务memcached.redis等. 伪静态,一般指在url上貌似访问静态html页的形式,这样有利于搜索引擎访问到网站页面,实际 ...

  2. ORA-00020:maximum number of processes (150) exceeded

    异常的含义 超过最大的进程数 我们使用下面的语句可以查看与进程(process)的相关参数: 如上所示,这里的最大进程数是150. 问题可能存在的原因 1.应用程序在使用数据库连接池时,使用完成后没有 ...

  3. Python从菜鸟到高手(2):清空Python控制台

    执行python命令会进入Python控制台.在Python控制台中可以用交互的方式执行Python语句.也就是执行一行Python语句,会立刻返回执行结果.   当Python控制台输入过多的Pyt ...

  4. JAVA CAS原理浅谈

    java.util.concurrent包完全建立在CAS之上的,没有CAS就不会有此包.可见CAS的重要性. CAS CAS:Compare and Swap, 翻译成比较并交换. java.uti ...

  5. C-代码笔记-输入输出

    .ACSII 字符实质和整数存储方式相同 //2018年9月16日01:35:54 # include <stdio.h> int main(void) { '; // printf(&q ...

  6. ecna2017-Game of Throwns

    这题就是给你一个标号为0-n-1的环,然后给你M个操作,操作有两种,一种是直接给一个数,这数的正负代表我当前向前(向后)仍了xx个位置的球,或者给你一个撤销操作表示为 undo m,表示撤销最近的M个 ...

  7. Leetcode——58.最后一个单词的长度

    给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度. 如果不存在最后一个单词,请返回 0 . 说明:一个单词是指由字母组成,但不包含任何空格的字符串. 示例: 输入: &quo ...

  8. 【软件工程Ⅱ】作业四 |个人项目-小学四则运算 “软件”之初版(C语言)

    本次作业的要求来自于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2186 本次作业代码的github地址:https://gith ...

  9. Maven入门指南④:仓库

    1 . 仓库简介 没有 Maven 时,项目用到的 .jar 文件通常需要拷贝到 /lib 目录,项目多了,拷贝的文件副本就多了,占用磁盘空间,且难于管理.Maven 使用一个称之为仓库的目录,根据构 ...

  10. jquery judge element exist

    http://learn.jquery.com/using-jquery-core/faq/how-do-i-test-whether-an-element-exists/ if ( $( " ...