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<algorithm>
  5 #include<cmath>
  6 #define N 1200005
  7 #define M 300005
  8 #define pi acos(-1)
  9 #define E complex
 10 using namespace std;
 11 struct complex
 12 {
 13     double x,y;
 14     complex(double _x,double _y){x=_x;y=_y;}
 15     complex(){;}
 16     friend complex operator * (const complex &a,const complex &b)
 17     {
 18         complex c;c.x=a.x*b.x-a.y*b.y;c.y=a.x*b.y+a.y*b.x;return c;
 19     }
 20     friend complex operator / (complex a,double b)
 21     {
 22         return complex(a.x/b,a.y/b);
 23     }
 24     friend complex operator + (complex a,complex b)
 25     {
 26         return complex(a.x+b.x,a.y+b.y);
 27     }
 28     friend complex operator - (complex a,complex b)
 29     {
 30         return complex(a.x-b.x,a.y-b.y);
 31     }
 32 };
 33 int R[N];int n;
 34 void fft(E *a,int f)
 35 {
 36     for(int i=0;i<n;i++)if(i<R[i])swap(a[i],a[R[i]]);
 37     for(int i=1;i<n;i<<=1)
 38     {
 39         E wn(cos(pi/i),f*sin(pi/i));
 40         for(int j=0;j<n;j+=(i<<1))
 41         {
 42             E w(1,0);
 43             for(int k=0;k<i;k++,w=w*wn)
 44             {
 45                 E x=a[j+k],y=w*a[j+k+i];
 46                 a[j+k]=x+y;a[j+k+i]=x-y;
 47             }
 48         }
 49     }
 50     if(f==-1)for(int i=0;i<n;i++)a[i]=a[i]/n;
 51 }
 52 int nn,mm;
 53 char s1[M],s2[M],s3[M];
 54 E a1[N],b1[N],c1[N];
 55 int ans[N];
 56 int st[M],top;
 57 int main()
 58 {
 59     scanf("%d%d",&nn,&mm);
 60     scanf("%s",s3);scanf("%s",s2);
 61     int l=0;
 62     for(n=1;n<2*mm;n<<=1)l++;
 63     for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(l-1));
 64     for(int i=0;i<nn;i++)s1[i]=s3[nn-i-1];
 65     for(int i=0;i<mm;i++)
 66     {
 67         int tmp=s2[i]-‘a‘+1;double p=tmp+0.0;
 68         if(s2[i]==‘*‘)p=0;
 69         b1[i].x=p;
 70     }
 71     for(int i=0;i<nn;i++)
 72     {
 73         int tmp=s1[i]-‘a‘+1;double p=tmp+0.0;
 74         if(s1[i]==‘*‘)p=0;
 75         a1[i].x=p*p*p;
 76     }
 77     fft(a1,1);fft(b1,1);
 78     for(int i=0;i<n;i++)c1[i]=a1[i]*b1[i];
 79     for(int i=0;i<n;i++)a1[i].x=a1[i].y=b1[i].x=b1[i].y=0;
 80
 81     for(int i=0;i<mm;i++)
 82     {
 83         int tmp=s2[i]-‘a‘+1;double p=tmp+0.0;
 84         if(s2[i]==‘*‘)p=0;
 85         b1[i].x=p*p;
 86     }
 87     for(int i=0;i<nn;i++)
 88     {
 89         int tmp=s1[i]-‘a‘+1;double p=tmp+0.0;
 90         if(s1[i]==‘*‘)p=0;
 91         a1[i].x=p*p;
 92     }
 93     fft(a1,1);fft(b1,1);
 94     for(int i=0;i<n;i++)c1[i]=c1[i]-(a1[i]*b1[i]),c1[i]=c1[i]-(a1[i]*b1[i]);
 95     for(int i=0;i<n;i++)a1[i].x=a1[i].y=b1[i].x=b1[i].y=0;
 96
 97     for(int i=0;i<mm;i++)
 98     {
 99         int tmp=s2[i]-‘a‘+1;double p=tmp+0.0;
100         if(s2[i]==‘*‘)p=0;
101         b1[i].x=p*p*p;
102     }
103     for(int i=0;i<nn;i++)
104     {
105         int tmp=s1[i]-‘a‘+1;double p=tmp+0.0;
106         if(s1[i]==‘*‘)p=0;
107         a1[i].x=p;
108     }
109     fft(a1,1);fft(b1,1);
110     for(int i=0;i<n;i++)c1[i]=c1[i]+(a1[i]*b1[i]);
111
112     fft(c1,-1);
113
114     for(int i=nn-1;i<mm;i++)
115     {
116         if(fabs(c1[i].x)<0.5)
117         {
118             st[++top]=i-nn+2;
119         }
120     }
121     printf("%d\n",top);
122     for(int i=1;i<=top;i++)
123     {
124         if(i!=top)printf("%d ",st[i]);
125         else printf("%d\n",st[i]);
126     }
127     return 0;
128 }
时间: 2024-10-14 20:44:12

bzoj 4259: 残缺的字符串的相关文章

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 #

【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]$

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;

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 残缺的字符串

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,从这

【BZOJ4259】 残缺的字符串

Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. 你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配? Input 第一行包含两个正整数m,n(1<=m<=n<=300000),分别表示A串和B串的长度. 第二行为一个长度为m的

P4173 残缺的字符串

\(\color{#0066ff}{ 题目描述 }\) 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串\(A\)和\(B\),其中\(A\)串长度为\(m\),\(B\)串长度为\(n\).可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. 你想对这两个串重新进行匹配,其中\(A\)为模板串,那么现在问题来了,请回答,对于\(B\)的每一个位置\(i\),从这个位置开始连续\(m\)个字符形成的子串是否可能与\(A\)串完全匹配? \(\col

【BZOJ】1856: [Scoi2010]字符串

http://www.lydsy.com/JudgeOnline/problem.php?id=1856 题意:把n个1和m个0组成字符串,要求在组成的字符串中,任意的前k个字符1的个数不能少于0的个数.求字符串共有多少个.(1<=m<=n<=1000000) #include <bits/stdc++.h> using namespace std; const int M=20100403; typedef long long ll; int mpow(int a, int