BZOJ 4259 残缺的字符串 ——FFT

【题目分析】

同bzoj4503。

只是精度比较卡,需要试一试才能行O(∩_∩)O

用过long double,也加过0.4。最后发现判断的时候改成0.4就可以了

【代码】

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define maxn 1200005
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)

const double pi=acos(-1.0);

struct Complex{
	double x,y;
	Complex operator + (Complex a){Complex b; return b.x=x+a.x,b.y=y+a.y,b;}
	Complex operator - (Complex a){Complex b; return b.x=x-a.x,b.y=y-a.y,b;}
	Complex operator * (Complex a){Complex b; return b.x=x*a.x-y*a.y,b.y=x*a.y+y*a.x,b;}
}a[maxn],b[maxn],c[maxn];

int A[maxn],B[maxn],la,lb,n,m=1,len,rev[maxn],ans[maxn],cnt=0;
char s1[maxn],s2[maxn];

void FFT(Complex * x,int n,int f)
{
	F(i,0,n-1) if (rev[i]>i) swap(x[rev[i]],x[i]);
	for (int m=2;m<=n;m<<=1)
	{
		int mid=m>>1;
		Complex wn; wn.x=cos(2.0*pi/m*f); wn.y=sin(2.0*pi/m*f);
		for (int i=0;i<n;i+=m)
		{
			Complex w; w.x=1.0; w.y=0;
			F(j,0,mid-1)
			{
				Complex a=x[i+j],b=x[i+j+mid]*w;
				x[i+j]=a+b; x[i+j+mid]=a-b;
				w=w*wn;
			}
		}
	}
}

int main()
{
//	freopen("in.txt","r",stdin);
	scanf("%d%d",&lb,&la);
	scanf("%s",s2);
	scanf("%s",s1);
	n=la+lb+1;
	while (m<=n) m<<=1,len++; n=m;
	F(i,0,n-1)
	{
		int t=i,ret=0;
		F(j,1,len) ret<<=1,ret|=t&1,t>>=1;
		rev[i]=ret;
	}
	F(i,0,la-1)	{A[i]=s1[i]-‘a‘+1; if (s1[i]==‘*‘) A[i]=0;}
	F(i,0,lb-1)	{B[i]=s2[lb-1-i]-‘a‘+1;	if (s2[lb-1-i]==‘*‘) B[i]=0;}

	F(i,0,n-1) a[i].x=A[i]*A[i]*A[i],a[i].y=0;
	F(i,0,n-1) b[i].x=B[i],b[i].y=0;
	FFT(a,n,1); FFT(b,n,1);
	F(i,0,n-1) c[i]=a[i]*b[i];

	F(i,0,n-1) a[i].x=A[i],a[i].y=0;
	F(i,0,n-1) b[i].x=B[i]*B[i]*B[i],b[i].y=0;
	FFT(a,n,1); FFT(b,n,1);
	F(i,0,n-1) c[i]=c[i]+a[i]*b[i];

	F(i,0,n-1) a[i].x=2*A[i]*A[i],a[i].y=0;
	F(i,0,n-1) b[i].x=B[i]*B[i],b[i].y=0;
	FFT(a,n,1); FFT(b,n,1);
	F(i,0,n-1) c[i]=c[i]-a[i]*b[i];

	FFT(c,n,-1);
	F(i,0,n-1) c[i].x=c[i].x/n;
//	F(i,0,n-1) printf("%.3f ",c[i].x); printf("\n");
	F(i,lb-1,la-1) if (fabs(c[i].x)<0.4) ans[++cnt]=i-lb+2;
	printf("%d\n",cnt);
	F(i,1,cnt) printf("%d%c",ans[i],i==cnt?‘\n‘:‘ ‘);
}

  

时间: 2024-10-13 04:55:33

BZOJ 4259 残缺的字符串 ——FFT的相关文章

bzoj 4259: 残缺的字符串

这题好神啊,居然是fft,表示一直在往数据结构上想. 把'*'当成0,那么两个串可以匹配当且仅当$$\sum (a[i]-b[i])^2\times a[i]\times b[i]==0$$ 我们可以把平方拆开,然后就变成了几个乘积相加的形式,那就大力翻转一个串然后跑FFT. 因为最开始MLE了所以复制粘贴了好多东西. 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<al

bzoj 4259 4259: 残缺的字符串【FFT】

和bzoj 4503 https://www.cnblogs.com/lokiii/p/10032311.html 差不多,就是再乘上一个原串字符 有点卡常,先在点值下算最后一起IDFT #include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int N=1100005; int n,m,bt,lm,re[N],tot;

【BZOJ】4259: 残缺的字符串

[题意]给定长度为m的匹配串B和长度为n的模板串A,求B在A中出现多少次.字符串仅由小写字母和通配符" * "组成,其中通配符可以充当任意一个字符.n<=3*10^5. [算法]FFT [题解]假设模板串的数组A用0~26代表所有字符,0为通配符,匹配串的数组B同理,那么用表示差异的经典套路: $$C_n=\sum_{i=0}^{m-1}(A_{n+i}-B_i)^2*A_{n+i}*B_i$$ 那么可以看出$C_n=0$当且仅当$S_A[n,n+m-1]=S_B[0,m-1]$

P4173 残缺的字符串 fft

题意:给你两个字符串,问你第一个在第二个中出现过多少次,并输出位置,匹配时是模糊匹配*可和任意一个字符匹配 题解:fft加速字符串匹配; 假设上面的串是s,s长度为m,下面的串是p,p长度为n,先考虑没有*的情况那么\(\sum_{j=1}^m(s_{i+j}-p_j)^2=0\)就表示能够从i开始匹配,现在考虑有*的情况,我们只需要让有*的和任意字符匹配即可,那么把公式变成\(\sum_{j=1}^m(s_{i+j}-p_j)^2*s_{i+j}*p_j)=0\),但是fft正向匹配太慢了,我

4259. 残缺的字符串

传送门 用 $FFT$ 搞字符串匹配,神仙操作.... 对于两个字符串 $A,B$,定义 $dis(A,B)=\sum_i(A_i-B_i)^2$ 显然当且仅当 $A=B$ 时,$dis(A,B)=0$ 这一题还有要求,'*' 为通配符,所以这题的 $dis(A,B)=\sum_i((A_i-B_i)^2[A_i!='*'][B_i!='*'])$ 发现这时如果设 '*' 为 $0$,则 $dis(A,B)=\sum_i((A_i-B_i)^2A_iB_i)$ 对于此题,设 $A$ 串为模板串,

luogu P4173 残缺的字符串 FFT

温馨提示:倘若下角标看不清的话您可以尝试放大. 倘若没有通配符的话可以用KMP搞一搞. 听巨佬说通配符可以用FFT搞一搞. 我们先考虑一下没有通配符的怎么搞.我们设a=1,b=2,...,然后我们构造一个这样的函数\(\displaystyle P_x=\sum_{i=0}^{m-1}(A_i-B_{x-m+1+i})^2\),但且仅当A和B在x的位置上匹配完成的时候$P_x $为0.至于为什么是平方,主要是为了防止正数和负数相互抵消. 至于通配符,我们设它为0,我们尝试重新构造一下\(\dis

Luogu P4173 残缺的字符串

P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C(x,y) =A(x)- B(y)\),若为0,表示B串中以第\(y\)个字符结尾的字符可以与A串中以\(x\)节为结尾的字符可以匹配 \(P(x) = \sum_{i = 0}^{m - 1}C(i,x - m + i + 1)\) 但是很遗憾当\(P(x)\),等于零时,只能够说明上述子串的字符

@bzoj - [email&#160;protected] 残缺的字符串

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. 你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这

BZOJ 4259 FFT

思路: 为什么好多字符串的题都可以用FFT啊.... 我们其实是要判断$\Sigma (a[i]-b[i])^2*a[i]*b[i]==0$ 那就把a串翻转过来 把 上式展开 大力做几遍FFT就好啦~ //By SiriusRen #include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define double long