BZOJ4259 残缺的字符串 【fft】
题目
很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。
你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?
输入格式
第一行包含两个正整数m,n(1<=m<=n<=300000),分别表示A串和B串的长度。
第二行为一个长度为m的字符串A。
第三行为一个长度为n的字符串B。
两个串均仅由小写字母和号组成,其中号表示相应位置已经残缺。
输出格式
第一行包含一个整数k,表示B串中可以完全匹配A串的位置个数。
若k>0,则第二行输出k个正整数,从小到大依次输出每个可以匹配的开头位置(下标从1开始)。
输入样例
3 7
a*b
aebr*ob
输出样例
2
1 5
题解
似乎字符串相关数据结构很难解决这个问题,我们考虑量化匹配关系
我们尝试构造两个多项式,
如果我们能让匹配的位置通过某种运算为0,似乎就能匹配了
如何构造?
如果两个位置匹配,要么这两个位置相等,要么为\(*\)
相等为0,容易想到减法
存在\(*\)就为0,容易想到*就表示0,然后乘起来
就成了这个样子:
\]
将其展开成为三个乘积相加的形式
我们将A串翻转,就可以三次fft计算了
#include<iostream>
#include<cstdio>
#include<cmath>
#include<complex>
#include<cstring>
#include<algorithm>
#define eps 1e-9
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 1200005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
const double pi = acos(-1);
struct E{
double r,i;
E(){}
E(double a,double b):r(a),i(b){}
E operator =(const int& b){
r = b; i = 0;
return *this;
}
};
inline E operator +(const E& a,const E& b){
return E(a.r + b.r,a.i + b.i);
}
inline E operator -(const E& a,const E& b){
return E(a.r - b.r,a.i - b.i);
}
inline E operator *(const E& a,const E& b){
return E(a.r * b.r - a.i * b.i,a.r * b.i + b.r * a.i);
}
inline E operator *=(E& a,const E& b){
return (a = a * b);
}
inline E operator /(E& a,const double& b){
return E(a.r / b,a.i / b);
}
inline E operator /=(E& a,const double& b){
return (a = a / b);
}
int n,m,L,R[maxn];
E A[maxn],B[maxn];
void fft(E* a,int f){
for (int i = 0; i < n; i++) if (i < R[i]) swap(a[i],a[R[i]]);
for (int i = 1; i < n; i <<= 1){
E wn(cos(pi / i),f * sin(pi / i));
for (int j = 0; j < n; j += (i << 1)){
E w(1,0);
for (int k = 0; k < i; k++,w *= wn){
E x = a[j + k],y = w * a[j + k + i];
a[j + k] = x + y; a[j + k + i] = x - y;
}
}
}
if (f == -1) for (int i = 0; i < n; i++) a[i] /= n;
}
char P[maxn],T[maxn];
int len,lm,ans[maxn],ansi;
double C[maxn];
void solve(){
int tmp;
for (int i = 0; i < n; i++) A[i] = B[i] = 0;
for (int i = 0; i < len; i++){
if (P[i] != '*'){
tmp = (P[i] - 'a' + 1);
A[i] = tmp * tmp * tmp;
}
}
for (int i = 0; i < lm; i++){
if (T[i] != '*'){
tmp = (T[i] - 'a' + 1);
B[i] = tmp;
}
}
fft(A,1); fft(B,1);
for (int i = 0; i < n; i++) A[i] *= B[i];
fft(A,-1);
for (int i = 0; i < n; i++) C[i] = floor(A[i].r + 0.5);
for (int i = 0; i < n; i++) A[i] = B[i] = 0;
for (int i = 0; i < len; i++){
if (P[i] != '*'){
tmp = (P[i] - 'a' + 1);
A[i] = tmp * tmp;
}
}
for (int i = 0; i < lm; i++){
if (T[i] != '*'){
tmp = (T[i] - 'a' + 1);
B[i] = tmp * tmp;
}
}
fft(A,1); fft(B,1);
for (int i = 0; i < n; i++) A[i] *= B[i];
fft(A,-1);
for (int i = 0; i < n; i++) C[i] -= 2 * floor(A[i].r + 0.5);
for (int i = 0; i < n; i++) A[i] = B[i] = 0;
for (int i = 0; i < len; i++){
if (P[i] != '*'){
tmp = (P[i] - 'a' + 1);
A[i] = tmp;
}
}
for (int i = 0; i < lm; i++){
if (T[i] != '*'){
tmp = (T[i] - 'a' + 1);
B[i] = tmp * tmp * tmp;
}
}
fft(A,1); fft(B,1);
for (int i = 0; i < n; i++) A[i] *= B[i];
fft(A,-1);
for (int i = 0; i < n; i++) C[i] += floor(A[i].r + 0.5);
}
int main(){
len = read(); lm = read();
scanf("%s",P);
scanf("%s",T);
for (int i = 0; i < (len >> 1); i++) swap(P[i],P[len - i - 1]);
m = len + lm - 2;
for (n = 1; n <= m; n <<= 1) L++;
for (int i = 0; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
solve();
for (int i = 0; i <= m; i++){
if (fabs(C[i]) < eps && i - len + 2 > 0 && i - len + 2 <= lm - len + 1){
ans[++ansi] = i - len + 2;
}
}
printf("%d\n",ansi);
for (int i = 1; i <= ansi; i++) printf("%d ",ans[i]);
return 0;
}
BZOJ4259 残缺的字符串 【fft】的更多相关文章
- BZOJ4259:残缺的字符串(FFT)
Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同 ...
- BZOJ4259: 残缺的字符串(FFT 字符串匹配)
题意 题目链接 Sol 知道FFT能做字符串匹配的话这就是个裸题了吧.. 考虑把B翻转过来,如果\(\sum_{k = 0}^M (B_{i - k} - A_k)^2 * B_{i-k}*A_k = ...
- luoguP4173 残缺的字符串 FFT
luoguP4173 残缺的字符串 FFT 链接 luogu 思路 和昨天做的题几乎一样. 匹配等价于(其实我更喜欢fft从0开始) \(\sum\limits_{i=0}^{m-1}(S[i+j]- ...
- Luogu P4173 残缺的字符串-FFT在字符串匹配中的应用
P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C ...
- P4173 残缺的字符串(FFT字符串匹配)
P4173 残缺的字符串(FFT字符串匹配) P4173 解题思路: 经典套路将模式串翻转,将*设为0,设以目标串的x位置匹配结束的匹配函数为\(P(x)=\sum^{m-1}_{i=0}[A(m-1 ...
- 【BZOJ4259】残缺的字符串 FFT
[BZOJ4259]残缺的字符串 Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时, ...
- BZOJ 4259: 残缺的字符串 [FFT]
4259: 残缺的字符串 题意:s,t,星号任意字符,匹配方案数 和上题一样 多乘上一个\(a_{j+i}\)就行了 #include <iostream> #include <cs ...
- CF528D Fuzzy Search 和 BZOJ4259 残缺的字符串
Fuzzy Search 给你文本串 S 和模式串 T,求 S 的每个位置是否能模糊匹配上 T. 这里的模糊匹配指的是把 T 放到 S 相应位置上之后,T 中每个字符所在位置附近 k 个之内的位置上的 ...
- 洛谷 P4173 残缺的字符串 (FFT)
题目链接:P4173 残缺的字符串 题意 给定长度为 \(m\) 的模式串和长度为 \(n\) 的目标串,两个串都带有通配符,求所有匹配的位置. 思路 FFT 带有通配符的字符串匹配问题. 设模式串为 ...
- BZOJ4259 残缺的字符串(FFT)
两个串匹配时相匹配的位置位置差是相同的,那么翻转一个串就变成位置和相同,卷积的形式. 考虑如何使用卷积体现两个位置能否匹配.一个暴力的思路是每次只考虑一种字符,将其在一个串中设为1,并在另一个串中将不 ...
随机推荐
- C#链接mysql 新手容易出错的问题
1.Access denied for user 'root'@'DESKTOP-AN72KEI' (using password: YES) 出现这个问题的原因是因为mysql的自带用户root理论 ...
- 2002-2003 ACM-ICPC Northeastern European Regional Contest (NEERC 02) H Heroes Of Might And Magic (隐含dp)
问题是求一个方案,实际隐含一个dp.法力是递减的,所以状态是DAG,对于一个确定的状态,我们贪心地希望英雄的血量尽量大. 分析:定义状态dp[i][p][h]表示是已经用了i的法力值,怪兽的位置在p, ...
- Core Data stack
https://developer.apple.com/library/content/documentation/DataManagement/Devpedia-CoreData/coreDataS ...
- DROP RULE - 删除一个重写规则
SYNOPSIS DROP RULE name ON relation [ CASCADE | RESTRICT ] DESCRIPTION 描述 DROP RULE 删除一个规则. PARAMETE ...
- iOS下的2D仿射变换机制(CGAffineTransform相关)
仿射变换简介 仿射变换源于CoreGraphics框架,主要作用是绘制2D级别的图层,几乎所有iOS设备屏幕上的界面元素都是由CoreGraphics来负责绘制.而我们要了解的2D仿射变换是其下负责二 ...
- Seek and Destroy-freecodecamp算法题目
Seek and Destroy(摧毁数组) 要求 实现一个摧毁(destroyer)函数,第一个参数是待摧毁的数组,其余的参数是待摧毁的值. 思路 利用for循环将输入arguments中除第一项待 ...
- Bzoj 近期题目一句话题解
目录 Bzoj 近期题目题解 1000: A+B Problem (模拟) 1008: [HNOI2008]越狱 (容斥) 1012: [JSOI2008]最大数maxnumber (线段树) 103 ...
- 初涉网络流[EK&dinic]
主要还是板子 Edmonds-Karp 从S开始bfs,直到找到一条到达T的路径后将该路径增广,并重复这一过程. 在处理过程中,为了应对“找到的一条路径把其他路径堵塞”的情况,采用了建反向弧的方式来实 ...
- 【计数】hdu5921Binary Indexed Tree
二进制拆位计算贡献 题目描述 树状数组是一种常用的数据结构,下面是树状数组用于给区间 [1,x] 内的数加 t 的代码: void add(int x,int t){ for (int i=x;i;i ...
- (70)zabbix telnet监控类型
概述 zabbix监控的方式很多,例如前面讲到的agent.snmp以及后续后续要讲到ssh和今天要讲到的telnet.流程很简单,创建item-->配置ip.用户.密码.端口.脚本->z ...