Description

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

Input

第一行包含两个正整数m,n(1<=m<=n<=300000),分别表示A串和B串的长度。
第二行为一个长度为m的字符串A。
第三行为一个长度为n的字符串B。
两个串均仅由小写字母和*号组成,其中*号表示相应位置已经残缺。

Output

第一行包含一个整数k,表示B串中可以完全匹配A串的位置个数。
若k>0,则第二行输出k个正整数,从小到大依次输出每个可以匹配的开头位置(下标从1开始)。

Sample Input

3 7
a*b
aebr*ob

Sample Output

2
1 5

HINT

 

Source

By Claris

Solution

对于每个字母的权值就设为1~26。*的权值设为0。两个字符可以匹配当且仅当A_i∗B_j∗(A_i−B_j )^2等于0。那么我们将这个式子展开,展开以后的每一项分别用FFT计算即可。

 #include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring> #define R register
#define maxn 1048576
typedef long double db;
const db pi = acosl(-);
char A[maxn], B[maxn];
struct Complex {
db x, y;
inline Complex operator - (const Complex &that) const {return (Complex) {x - that.x, y - that.y};}
inline Complex operator * (const Complex &that) const {return (Complex) {x * that.x - y * that.y, x * that.y + y * that.x};}
inline void operator += (const Complex &that) {x += that.x; y += that.y;}
} w[maxn];
int N;
void init()
{
R int h = N >> ;
for (R int i = ; i < h; ++i) w[i + h] = (Complex) {cos( * pi / N * i), sin( * pi / N * i)};
for (R int i = h; i--; ) w[i] = w[i << ];
}
void bit_reverse(R Complex *a, R Complex *b)
{
for (R int i = ; i < N; ++i) b[i] = a[i];
for (R int i = , j = ; i < N; ++i)
{
i > j ? std::swap(b[i], b[j]), : ;
for (R int l = N >> ; (j ^= l) < l; l >>= );
}
}
void dft(R Complex *a)
{
for (R int l = , m = ; m != N; l <<= , m <<= )
for (R int i = ; i < N; i += l)
for (R int j = ; j < m; ++j)
{
R Complex tmp = a[i + j + m] * w[j + m];
a[i + j + m] = a[i + j] - tmp;
a[i + j] += tmp;
}
}
Complex a[maxn], b[maxn], ta[maxn], tb[maxn], tc[maxn], ans[maxn];
int aa[maxn], bb[maxn];
int main()
{
R int la, lb;
scanf("%s%s", A, B);
la = strlen(A); lb = strlen(B);
for (N = ; N < (la + lb); N <<= );
init();
std::reverse(A, A + la);
for (R int i = ; i < la; ++i) A[i] == '*' ? : aa[i] = A[i] - 'a' + ;
for (R int i = ; i < lb; ++i) B[i] == '*' ? : bb[i] = B[i] - 'a' + ; for (R int i = ; i < la; ++i) a[i].x = aa[i] * aa[i] * aa[i], a[i].y = ;
for (R int i = ; i < lb; ++i) b[i].x = bb[i], b[i].y = ;
bit_reverse(a, ta); bit_reverse(b, tb);
dft(ta); dft(tb);
for (R int i = ; i < N; ++i) ans[i] += (ta[i] * tb[i]); for (R int i = ; i < la; ++i) a[i].x = - * aa[i] * aa[i], a[i].y = ;
for (R int i = ; i < lb; ++i) b[i].x = bb[i] * bb[i], b[i].y = ;
bit_reverse(a, ta); bit_reverse(b, tb);
dft(ta); dft(tb);
for (R int i = ; i < N; ++i) ans[i] += (ta[i] * tb[i]); for (R int i = ; i < la; ++i) a[i].x = aa[i], a[i].y = ;
for (R int i = ; i < lb; ++i) b[i].x = bb[i] * bb[i] * bb[i], b[i].y = ;
bit_reverse(a, ta); bit_reverse(b, tb);
dft(ta); dft(tb);
for (R int i = ; i < N; ++i) ans[i] += (ta[i] * tb[i]); std::reverse(ans + , ans + N);
bit_reverse(ans, tc);
dft(tc);
// for (R int i = 0; i < N; ++i) printf("%lf %lf\n", tc[i].x, tc[i].y);
for (R int i = la - ; i < lb; ++i) if (fabs(tc[i].x / N) < 0.5) printf("%d ", i - la + );
return ;
}
/*
399906 399924 399942 399960 399978 399996
*/

FFT

其实这题的数据用bitset是可以水过的。不过可以卡。然后我优化了一发常数就只是最慢的数据本机3s以内了。我把代码放在这里欢迎大家来hack!  O(∩_∩)O~~

 #include <cstdio>
#include <cstring>
#include <bitset>
#include <algorithm> #define R register
#define maxn 500010
#define maxs 15635
//#define inline
char A[maxn], B[maxn];
/*inline bool eq(R char a, R char b)
{
return a == b || a == '*' || b == '*';
}*/
typedef unsigned uint;
int len; #define set(v, x) (v[x >> 5] |= 1u << (x & 31))
#define query(v, x) ((1u << (x & 31)) & v[x >> 5])
uint p[][][maxs];
uint aph[][maxs], ans[maxs];
inline void init(R int c)
{
R uint *t = p[c][], *tt;
for (R int i = ; i <= len; ++i) t[i] = aph[c][i];
for (R int i = ; i < ; ++i)
{
t = p[c][i]; tt = p[c][i - ];
for (R int j = ; j <= len; ++j)
t[j] = ((tt[j] >> ) | ((tt[j + ] & 1u) << ));
}
}
int cnt;
inline void bit_and(R int c, R int l)
{
R int fir = l >> ; R uint *t = p[c][l & ];
R int i = fir, j = ;
for (; i + < len; i += , j += )
{
ans[j] &= t[i];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
ans[j + ] &= t[i + ];
}
for (; i <= len; ++i, ++j) ans[j] &= t[i];
} //std::bitset<maxn> aph[26], ans;
int fail[maxn];
int r[maxn];
inline bool cmp(R int a, R int b) {return A[a] < A[b] || (A[a] == A[b] && (a & ) < (b & ));}
int main()
{
// freopen("str.in", "r", stdin);
// freopen("str.out", "w", stdout);
scanf("%s%s", A, B);
R int la = strlen(A), lb = strlen(B);
len = lb >> ;
R int xcnt = ;
for (R int i = ; i < la; ++i) xcnt += A[i] == '*';
for (R int i = ; i < lb; ++i) xcnt += B[i] == '*';
/*if (!xcnt)
{
fail[1] = 0;
for (R int i = la; i; --i) A[i] = A[i - 1];
for (R int i = lb; i; --i) B[i] = B[i - 1];
for (R int i = 2, p = 0; i <= la; ++i)
{
while (p && A[p + 1] != A[i]) p = fail[p];
A[p + 1] == A[i] ? ++p : 0;
fail[i] = p;
}
for (R int i = 1, p = 0; i <= lb; ++i)
{
while (p && A[p + 1] != B[i]) p = fail[p];
A[p + 1] == B[i] ? ++p : 0;
if (p == la)
{
printf("%d ", i - la + 1);
p = fail[p];
}
}
puts("");
return 0;
}*/
for (R int i = ; i < lb; ++i)
{
if (B[i] != '*') set(aph[B[i] - 'a'], i);
else for (R int j = ; j < ; ++j) set(aph[j], i);
set(ans, i);
}
for (R int i = ; i < ; ++i) init(i);
// fprintf(stderr, "%d %d\n", '*', 'a');
for (R int i = ; i < la; ++i) r[i] = i;
std::sort(r, r + la, cmp);
for (R int i = ; i < la; ++i)
if (A[r[i]] != '*')
bit_and(A[r[i]] - 'a', r[i]);
// ans &= (aph[A[i] - 'a'] >> i);
for (R int i = ; i + la - < lb; ++i) if (query(ans, i)) printf("%d ", i + ); puts("");
return ;
}

bitset

【BZOJ4259】 残缺的字符串的更多相关文章

  1. CF528D Fuzzy Search 和 BZOJ4259 残缺的字符串

    Fuzzy Search 给你文本串 S 和模式串 T,求 S 的每个位置是否能模糊匹配上 T. 这里的模糊匹配指的是把 T 放到 S 相应位置上之后,T 中每个字符所在位置附近 k 个之内的位置上的 ...

  2. BZOJ4259残缺的字符串

    题目描述 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. ...

  3. BZOJ4259 残缺的字符串(FFT)

    两个串匹配时相匹配的位置位置差是相同的,那么翻转一个串就变成位置和相同,卷积的形式. 考虑如何使用卷积体现两个位置能否匹配.一个暴力的思路是每次只考虑一种字符,将其在一个串中设为1,并在另一个串中将不 ...

  4. BZOJ4259:残缺的字符串(FFT)

    Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同 ...

  5. BZOJ4259 残缺的字符串 【fft】

    题目 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. 你想 ...

  6. BZOJ4259: 残缺的字符串 & BZOJ4503: 两个串

    [传送门:BZOJ4259&BZOJ4503] 简要题意: 给出两个字符串,第一个串长度为m,第二个串长度为n,字符串中如果有*字符,则代表当前位置可以匹配任何字符 求出第一个字符串在第二个字 ...

  7. BZOJ4259 残缺的字符串 多项式 FFT

    原文链接http://www.cnblogs.com/zhouzhendong/p/8798532.html 题目传送门 - BZOJ4259 题意 给你两个串,用其中一个来匹配另一个.问从母串的那些 ...

  8. [BZOJ4259]残缺的字符串

    Description: 给定两个带通配符的串,求可能出现几次匹配,以及这些匹配位置 Hint: \(n \le 3*10^5\) Solution: 定义匹配函数 \(P(x)=\sum_{i=x} ...

  9. 2018.11.17 bzoj4259: 残缺的字符串(fft)

    传送门 fftfftfft套路题. 我们把aaa ~ zzz映射成111 ~ 262626,然后把∗*∗映射成000. 考虑对于两个长度都为nnn的字符串A,BA,BA,B. 我们定义一个差异函数di ...

  10. BZOJ4259: 残缺的字符串(FFT 字符串匹配)

    题意 题目链接 Sol 知道FFT能做字符串匹配的话这就是个裸题了吧.. 考虑把B翻转过来,如果\(\sum_{k = 0}^M (B_{i - k} - A_k)^2 * B_{i-k}*A_k = ...

随机推荐

  1. windows10 AppStore安装 应用商店重新安装

    点击左下角的搜索按钮,如下图所示   输入powershell,在结果中找到widows powershell应用,如下图所示   右键单击widows powershell应用,选择以管理员运行,如 ...

  2. 小菜鸟之JAVA面试题库1

    四次挥手 客户端发送释放连接报文,关闭客户端到服务端的数据传输 服务端收到后,发送确认报文给客户端 服务端发送释放连接报文,关闭服务端到客户端的数据传输 客户端发送一个确认报文给服务端 ------- ...

  3. MySQL中关于主从数据库同步延迟的问题解决

    MySQL的主从同步是一个很成熟的架构,优点为:①在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力;②在从主服务器进行备份,避免备份期间影响主服务器服务;③当主服务器出现问题时,可以 ...

  4. mysql5.6 多实例标准化安装

    1.检查防火墙 是否关闭service iptables stopchkconfig iptables offservice iptables status 2. SELINUXvim /etc/se ...

  5. Java后端技术面试汇总(第一套)

    面试汇总,整理一波,doc文档可点击[此处下载] 1.基础篇 1.1.Java基础 • 面向对象的特征:继承.封装和多态• final, finally, finalize 的区别• Exceptio ...

  6. Linq Distinct 自定义比较

    private class MyMenuComparer : IEqualityComparer { public bool Equals(ParMenu x, ParMenu y){ return ...

  7. nodejs---crypto模块MD5签名

    1.MD5是一种常用的哈希算法,用于给任意数据一个“签名”.这个签名通常用一个十六进制的字符串表示: /*md5签名*/ /*引入crypto模块*/ const crypto = require(' ...

  8. 平时工作使用到的idea快捷键或者技巧

    平时工作使用到的idea快捷键或者技巧 alt+enter 快速导入包 alt+insert 快速生成setter和getter ctrl+alt+l 格式化代码 /**然后回车 快速生成文档注释 a ...

  9. js css3 固定点拖拽旋转

    一.直接上效果图: 然后是代码: 一共两种实现方式: <!DOCTYPE html> <html lang="en"> <head> <m ...

  10. call,apply,bind的理解

    call,apply,bind均是用于改变this指向. 三者相似之处: 1:都是用于改变函数的this指向. 2:第一个参数都是this要指向的对象. 3:都可以通过后面的参数进行对方法的传参. l ...