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. CSS进阶知识

    html { -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; } 该属性的作用是 ...

  2. JQuery和Servlet来实现跨域请求

    在网上看到很多的JQuery跨域请求的文章,比较有意思.这里我发表一个Servlet与JQuery配置实现跨域的代码,供大家参考.不足之处请指教 原理:JavaScript的Ajax不可以跨域,但是可 ...

  3. ASP.Net中表单POST到其他页面的方法

    在ASP中,我们通常把表单提交到另外一个页面(接受数据页面).但是在ASP.NET中,服务端表单通常都是提交到本页面的,如果我设置 form1.action="test.aspx" ...

  4. DOM基础操作

    本文地址:http://www.cnblogs.com/veinyin/p/7606972.html  1 访问 HTML 元素 常用方法 document.getElementById(" ...

  5. NYOJ 208 Supermarket (模拟+并查集)

    题目链接 描述 A supermarket has a set Prod of products on sale. It earns a profit px for each product x∈Pr ...

  6. Hibernate总结之常用API

    1. Configuration Configuration是用来读取配置文件,从配置文件中构件SessionFactory的. SessionFactory sessionFactory=new C ...

  7. python基础===用9种方式生成新的对象

    class Point: def __init__(self, x, y): self.x = x self.y = y point1 = Point(1, 2) point2 = eval(&quo ...

  8. 大数据系列之kafka-java实现

    Java源码GitBub地址: https://github.com/fzmeng/kafka-demo 关于kafka安装步骤可见文章   http://www.cnblogs.com/cnmeng ...

  9. [转载]理解Tomcat的Classpath-常见问题以及如何解决

    摘自: http://www.linuxidc.com/Linux/2011-08/41684.htm 在很多Apache Tomcat用户论坛,一个问题经常被提出,那就是如何配置Tomcat的cla ...

  10. c++输出保留固定小数位数

    cout<<setprecision(6)<<fixed<<ans<<endl;