4503: 两个串

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 497  Solved: 226

Description

兔子们在玩两个串的游戏。给定两个字符串S和T,兔子们想知道T在S中出现了几次,
分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。

Input

两行两个字符串,分别代表S和T

Output

第一行一个正整数k,表示T在S中出现了几次
接下来k行正整数,分别代表T每次在S中出现的开始位置。按照从小到大的顺序输出,S下标从0开始。

Sample Input

bbabaababaaaaabaaaaaaaabaaabbbabaaabbabaabbbbabbbbbbabbaabbbababababbbbbbaaabaaabbbbbaabbbaabbbbabab
a?aba?abba

Sample Output

0

HINT

S 长度不超过 10^5, T 长度不会超过 S。 S 中只包含小写字母, T中只包含小写字母和“?”

Source

【分析】

  这题做了我好久啊。。幸好1A,哭死了。。

  首先,是不可以用KMP的,【我一开始还觉得可以】

  因为你根据第二个串求next可能会以'?'为媒介,认为'a'与'b'相同什么的。

  小山羊说,大多数含'?'的字符串的题目都不可以用KMP,EXKMP,AC自动机,后缀数组等等字符串匹配方法,就会出现上面说的问题。不过我觉得如果这题的'?'是在第一个串上的话,应该是可以用的。

  所以怎么办呢?FFT大法。

  很容易想到一个方法就是类似‘万径人踪灭’那里的。做26次FFT,每次把一个字母标为1,其他标为0,看一看匹配长度是否为m,但是会超时?【并没有实测过

  不过这题只是问你能否完全匹配,并没有问你匹配多少个字符之类的。

  所以可以构造这么一个函数。设$a[i]=s[i]=='?'?0:a[i]-'a'+1$。

  则$ans[i+j]=(a[i]-b[j])^{2}*b[j]$

  当且仅当全部匹配,ans为0,后面乘a[j]是搞'?'的。

  这个也很显然吧。

  但是!!!注意这个式子啊,不能把a,b化成点值表示就直接乘,否则意义就会变成

  $ans[i+i+j]+=a[i]^{2}*a[j]; ans[j+j+j]+=a[j]^{3}; ans[i+j+j]+=-2*a[i]*a[j]^{2}$意义完全不对。

  我还是理解了好久才发现这个错啊,以后不能再错这个了!!!

  所以你要分几次搞,令$A[i]=a[i]^2$,$B[i]=b[i]^2$,$C[i]=1$,$D[i]=b[i]^{3}$

  则$ans=A*b+C*D-2*a*B$

  FFT加速即可【为什么我跑得那么慢并且代码那么丑?

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define Maxn 100010*4
const double pi=acos(-); char s1[Maxn],s2[Maxn];
int aa[Maxn],bb[Maxn]; struct P
{
double x,y;
P() {x=y=;}
P(double x,double y):x(x),y(y){}
friend P operator + (P x,P y) {return P(x.x+y.x,x.y+y.y);}
friend P operator - (P x,P y) {return P(x.x-y.x,x.y-y.y);}
friend P operator * (P x,P y) {return P(x.x*y.x-x.y*y.y,x.x*y.y+x.y*y.x);}
friend P operator * (P x,int y) {return P(x.x*y,x.y*y);}
}a[Maxn],b[Maxn]; int nn,R[Maxn],op[Maxn],ans[Maxn];
void fft(P *s,int f)
{
for(int i=;i<nn;i++) if(i<R[i]) swap(s[i],s[R[i]]);
for(int i=;i<nn;i<<=)
{
P wn(cos(pi/i),f*sin(pi/i));
for(int j=;j<nn;j+=i<<)
{
P w(,);
for(int k=;k<i;k++,w=w*wn)
{
P x=s[j+k],y=w*s[j+k+i];
s[j+k]=x+y;s[j+k+i]=x-y;
}
}
}
if(f==-)
{
for(int i=;i<=nn;i++) s[i].x=s[i].x/nn;
}
} int main()
{
scanf("%s%s",s1,s2);
int n=strlen(s1),m=strlen(s2);
n--;m--;
for(int i=;i<=n;i++) aa[i]=s1[i]=='?'?:(s1[i]-'a'+);
for(int i=;i<=m;i++) bb[m-i]=s2[i]=='?'?:(s2[i]-'a'+);
int ll=;nn=;
while(nn<=n+m) ll++,nn<<=;
for(int i=;i<nn;i++) R[i]=(R[i>>]>>)|((i&)<<(ll-)); for(int i=;i<=n;i++) a[i].x=aa[i]*aa[i];
for(int i=;i<=m;i++) b[i].x=bb[i];
fft(a,);fft(b,);
for(int i=;i<=nn;i++) a[i]=a[i]*b[i];
fft(a,-);
memset(ans,,sizeof(ans));
for(int i=;i<=n+m;i++) ans[i]+=(int)(a[i].x+0.5);
// for(int i=0;i<=n+m;i++) printf("%d ",ans[i]); for(int i=;i<=nn;i++) a[i].x=a[i].y=b[i].x=b[i].y=;
for(int i=;i<=n;i++) a[i].x=;
for(int i=;i<=m;i++) b[i].x=bb[i]*bb[i]*bb[i];
fft(a,);fft(b,);
for(int i=;i<=nn;i++) a[i]=a[i]*b[i];
fft(a,-);
for(int i=;i<=n+m;i++) ans[i]+=(int)(a[i].x+0.5);
// for(int i=0;i<=n+m;i++) printf("%d ",ans[i]); for(int i=;i<=nn;i++) a[i].x=a[i].y=b[i].x=b[i].y=;
for(int i=;i<=n;i++) a[i].x=*aa[i];
for(int i=;i<=m;i++) b[i].x=bb[i]*bb[i];
fft(a,);fft(b,);
for(int i=;i<=nn;i++) a[i]=a[i]*b[i];
fft(a,-);
for(int i=;i<=n+m;i++) ans[i]-=(int)(a[i].x+0.5);
// for(int i=0;i<=n+m;i++) printf("%d ",ans[i]);printf("\n"); op[]=;
for(int i=m;i<=n;i++) if(!ans[i])
{
op[++op[]]=i-m;
}
printf("%d\n",op[]);
for(int i=;i<=op[];i++) printf("%d\n",op[i]);
return ;
}

2017-04-14 2017-04-14

【BZOJ 4503】4503: 两个串 (FFT)的更多相关文章

  1. BZOJ 4503: 两个串 [FFT]

    4503: 两个串 题意:兔子们在玩两个串的游戏.给定两个只含小写字母的字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有"?"字符,这个字符可以匹 ...

  2. 【bzoj4259/bzoj4503】残缺的字符串/两个串 FFT

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

  3. 【BZOJ4503】两个串 FFT

    [BZOJ4503]两个串 Description 兔子们在玩两个串的游戏.给定两个字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有“?”字符,这个字符可以匹配任何字 ...

  4. BZOJ.4503.两个串(FFT/bitset)

    题目链接 \(Description\) 给定两个字符串S和T,求T在S中出现了几次,以及分别在哪些位置出现.T中可能有'?'字符,这个字符可以匹配任何字符. \(|S|,|T|\leq 10^5\) ...

  5. bzoj 4503 两个串——FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4503 翻转T,就变成卷积.要想想怎么判断. 因为卷积是乘积求和,又想到相等的话相减为0,所以 ...

  6. bzoj 4503 两个串 —— FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4503 推式子即可: 不知怎的调了那么久,应该是很清晰的. 代码如下: #include< ...

  7. BZOJ 4503 两个串 ——FFT

    [题目分析] 定义两个字符之间的距离为 (ai-bi)^2*ai*bi 如果能够匹配,从i到i+m的位置的和一定为0 但这和暴力没有什么区别. 发现把b字符串反过来就可以卷积用FFT了. 听说KMP+ ...

  8. 【bzoj4503】 两个串 FFT

    $FFT$套路题(然而我看错题了) 我们考虑化一下式子. 设当前比较的两个部分为$S[i....i+|T|-1]$和$T[0....|T|-1]$. 我们对串$T$中出现问号的位置全部赋值为$0$. ...

  9. bzoj 4503 两个串

    Description 兔子们在玩两个串的游戏.给定两个字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有“?”字符,这个字符可以匹配任何字符. Input 两行两个字 ...

随机推荐

  1. jquery 事件对象属性小结

    使用事件自然少不了事件对象. 因为不同浏览器之间事件对象的获取, 以及事件对象的属性都有差异, 导致我们很难跨浏览器使用事件对象. jQuery中统一了事件对象, 当绑定事件处理函数时, 会将jQue ...

  2. 【BZOJ】1426: 收集邮票 期望DP

    [题意]有n种不同的邮票,第i次可以花i元等概率购买到一种邮票,求集齐n种邮票的期望代价.n<=10^4. [算法]期望DP [题解]首先设g[i]表示已拥有i张邮票集齐的期望购买次数,根据全期 ...

  3. CodeForces 990C

    Description A bracket sequence is a string containing only characters "(" and ")" ...

  4. 通过cordova将vue项目打包为webapp

    准备工作:需要之前配置好vue-cli脚架构,安装好cordova环境.下面开始对vue.js项目进行打包,打包环境为Android. 可以看下我的github:https://github.com/ ...

  5. NASA: A Closer View of the Moon(近距离观察月球)

    Posted to Twitter by @Astro_Alex, European Space Agency astronaut Alexander Gerst, this image shows ...

  6. C++ Class与Struct的区别

    转自某楼层的回复http://bbs.csdn.net/topics/280085643 首先,讨论这个问题应该仅从语法上讨论,如果讨论不同人之间编程风格上的差异,那这个问题是没有答案的.毕竟不同的人 ...

  7. PHY Linux 驱动

    以太网 MAC(链路层)+PHY(物理层/RTL8201F,88E1111);集成型DM9000,RTL8139CP 由于网络数据传输量较大,不论是分开型还是集成型,通常会在MAC和PHY之间引入DM ...

  8. FusionCharts 用法心得

    现在主流的很多jQuery+js结合的图表展示插件,有HighCharts,ECharts等等,今天我们先来了解一下FusionCharts,也是一个非常不错的图表制作工具.希望我的同事以及其他需要帮 ...

  9. U3D的一些常用基础脚本

    修改渲染颜色和贴图 1: var texture :Texture ; 2:  3: function Start () { 4: renderer.material.mainTexture = te ...

  10. Merge k Sorted Lists——分治与堆排序(需要好好看)

    Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 1 ...