bzoj 4503 两个串 fft

两个串

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 1078  Solved: 434
[Submit][Status][Discuss]

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中只包含小写字母和“?”

 
题解:判断两个串,第二个在第一个中出现次数,这类问题ac自动机,kmp
   但是第二个串有通配符,这个应该怎么办,其实可以这样判,就是对于
   这个就是个卷积的形式,对于通配符就是如果是的话就直接为0,就是再乘个数的问题吧,将第二个串反一下就是个卷积了。
 1 #include<cstring>
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cmath>
 6 
 7 #define ll long long
 8 #define N 100007
 9 #define pi acos(-1)
10 using namespace std;
11 inline int read()
12 {
13     int x=0,f=1;char ch=getchar();
14     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
15     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
16     return x*f;
17 }
18 
19 int n,m,res,num,L;
20 double hjq;
21 int c[N],d[N],rev[N];
22 ll ans[N<<2];
23 char ch[N];
24 
25 struct comp
26 {
27     double r,v;
28     comp(){}
29     comp(double a,double b){r=a,v=b;}
30     friend inline comp operator+(comp x,comp y){return comp(x.r+y.r,x.v+y.v);}
31     friend inline comp operator-(comp x,comp y){return comp(x.r-y.r,x.v-y.v);}
32     friend inline comp operator*(comp x,comp y){return comp(x.r*y.r-x.v*y.v,x.r*y.v+x.v*y.r);}
33 }a1[N<<2],b1[N<<2],a2[N<<2],b2[N<<2],fzy[N<<2];
34 
35 void FFT(comp *a,int flag)
36 {
37     for (int i=0;i<num;i++)
38         if (i<rev[i]) swap(a[i],a[rev[i]]);
39     for (int i=1;i<num;i<<=1)
40     {
41         comp wn=comp(cos(pi/i),flag*sin(pi/i));
42         for (int j=0;j<num;j+=(i<<1))
43         {
44             comp w=comp(1,0);
45             for (int k=0;k<i;k++,w=w*wn)
46             {
47                 comp x=a[j+k],y=w*a[j+k+i];
48                 a[j+k]=x+y,a[j+k+i]=x-y;
49             }
50         }
51     }
52     if (flag==-1) for (int i=0;i<num;i++) a[i].r/=num; 
53 }
54 int main()
55 {
56     scanf("%s",ch),n=strlen(ch);
57     for (int i=0;i<n;i++) c[i]=ch[i]-'a'+1;
58     scanf("%s",ch),m=strlen(ch);
59     for (int i=0;i<m;i++) d[i]=(ch[m-i-1]=='?')?0:ch[m-i-1]-'a'+1;
60     
61     for (int i=0;i<n;i++) a1[i].r=1.0*c[i]*c[i];
62     for (int i=0;i<m;i++) b1[i].r=1.0*d[i];
63     for (int i=0;i<n;i++) a2[i].r=-2.0*c[i];
64     for (int i=0;i<m;i++) b2[i].r=1.0*d[i]*d[i];
65     for (int i=0;i<m;i++) hjq+=d[i]*d[i]*d[i];
66     
67     
68     for (num=1;num<=n+m-1;num<<=1,L++);if (L) L--;
69     for (int i=0;i<num;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<L);
70     FFT(a1,1),FFT(b1,1),FFT(a2,1),FFT(b2,1);
71     for (int i=0;i<num;i++) fzy[i]=a1[i]*b1[i]+a2[i]*b2[i];
72     FFT(fzy,-1);
73     for (int i=0;i<num;i++) ans[i]=(ll)(hjq+fzy[i].r+0.5);
74     for (int i=m-1;i<n;i++) if (!ans[i]) res++;
75     printf("%d\n",res);
76     for (int i=m-1;i<n;i++)
77         if (!ans[i]) printf("%d\n",i-m+1);
78 }

 

posted @ 2018-03-31 14:11  Kaiser-  阅读(133)  评论(0编辑  收藏  举报