傳送門
文章目錄
題意:
n,m,k≤2e5n,m,k\le2e5n,m,k≤2e5
思路:
直接考慮fftfftfft來匹配字符串。
由于kkk是給定的,所以難度低了很多,普通的字符串匹配不能處理這種可以范圍相等的情況,看到字符集出奇的小,考慮將其拆開來看。
單獨看某個字符的時候,考慮將字符串轉換成010101串進行匹配。轉換的時候只需要將當前字符的周圍kkk個字符都變成當前字符即可,讓后之前將bbb翻轉一下就可以直接卷了,原理與之前寫的博客相同。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6,PI
=acos(-1);int n
,m
,k
;
char aa
[N
],bb
[N
];
int pre
[N
][26],f
[N
];
int A
[N
],B
[N
];
string s
;
int rev
[N
];
int bit
,limit
;struct Complex {double x
,y
;Complex
operator + (const Complex
& t
) const { return {x
+t
.x
,y
+t
.y
}; }Complex
operator - (const Complex
& t
) const { return {x
-t
.x
,y
-t
.y
}; }Complex
operator * (const Complex
& t
) const { return {x
*t
.x
-y
*t
.y
,x
*t
.y
+y
*t
.x
}; }
}a
[N
],b
[N
];void fft(Complex a
[],int inv
) {for(int i
=0;i
<limit
;i
++) if(i
<rev
[i
]) swap(a
[i
],a
[rev
[i
]]);for(int mid
=1;mid
<limit
;mid
<<=1) {Complex w1
=Complex({cos(PI
/mid
),inv
*sin(PI
/mid
)});for(int i
=0;i
<limit
;i
+=mid
*2) {Complex wk
=Complex({1,0});for(int j
=0;j
<mid
;j
++,wk
=wk
*w1
) {Complex x
=a
[i
+j
],y
=wk
*a
[i
+j
+mid
];a
[i
+j
]=x
+y
; a
[i
+j
+mid
]=x
-y
;}}}
}int main()
{
s
="ATGC";cin
>>n
>>m
>>k
>>aa
>>bb
;for(int i
=0;i
<n
;i
++) {for(int j
=0;j
<4;j
++) pre
[i
][j
]=pre
[max(i
-1,0)][j
]+(aa
[i
]==s
[j
]);}while((1<<bit
)<=n
+m
) bit
++;limit
=1<<bit
;for(int i
=0;i
<limit
;i
++) rev
[i
]=(rev
[i
>>1]>>1)|((i
&1)<<(bit
-1));reverse(bb
,bb
+m
);for(int i
=0;i
<4;i
++) {char ch
=s
[i
];for(int j
=0;j
<m
;j
++) B
[j
]=bb
[j
]==ch
;for(int j
=0;j
<n
;j
++) {A
[j
]=0;int l
=max(0,j
-k
),r
=min(n
-1,j
+k
);int cnt
=pre
[r
][i
]-(l
-1>=0? pre
[l
-1][i
]:0);if(aa
[j
]==ch
) cnt
=1;if(cnt
>0) A
[j
]=1;}for(int i
=0;i
<limit
;i
++) a
[i
]=b
[i
]={0,0};for(int i
=0;i
<n
;i
++) a
[i
]={1.0*A
[i
],0};for(int i
=0;i
<m
;i
++) b
[i
]={1.0*B
[i
],0};fft(a
,1); fft(b
,1);for(int i
=0;i
<limit
;i
++) a
[i
]=a
[i
]*b
[i
];fft(a
,-1);for(int i
=m
-1;i
<n
;i
++) {int now
=(int)(a
[i
].x
/limit
+0.5);f
[i
-m
+1]+=now
;}}int ans
=0;for(int i
=0;i
<n
;i
++) {if(f
[i
]==m
) ans
++;}printf("%d\n",ans
);return 0;
}
總結
以上是生活随笔為你收集整理的Codeforces Round #296 (Div. 1) D. Fuzzy Search FFT匹配字符串的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。