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. Oracle-DDL 2- 视图&索引

    DDL-数据定义语句: 二.视图 --视图(view),本身不保存数据,保存的是一个查询语句--对视图的操作等同于对查询语句中源数据的操作--视图占用存储空间较小,可以快速的对特定数据进行访问和操作- ...

  2. 设计模式:策略模式(Stratege)

    首先我们需要知道策略模式与状态模式是如此的相似,就犹如一对双胞胎一样.只不过状态模式是通过改变对象内部的状态来帮助对象控制自己的行为,而策略模式则是围绕可以互换的算法来创建成功业务的.两者都可用于解决 ...

  3. six库 解决python2的项目如何能够完全迁移到python3

    six库 解决python2的项目如何能够完全迁移到python3 SIX是用于python2与python3兼容的库. 它存在的目的是为了拥有无需修改即可在Python 2和Python 3上同时工 ...

  4. 如何用纯 CSS 创作六边形按钮特效

    效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/xjoOeM 可交互视频教 ...

  5. ps -ef

    status, msg = commands.getstatusoutput("ps -ef | grep start.sh | grep -Fv grep | awk '{print $1 ...

  6. 数据绑定-POJO对象绑定参数

    测试: 效果:

  7. whistle 前端工具之抓包利器

    一.业务场景 前端本地开发的场景中,我们需要频繁的改动代码,并需要实时看到效果,并且在一些开发场景中,我们需要将特定的请求代理到特定的IP.本地文件等,所以使用fiddler或whistle等本地.真 ...

  8. 线程的函数中调用MFC对话框类的变量

    线程的函数中调用MFC对话框类的变量多线程传输文件的对话框 现在想要在对话框上添加一个进度条 为进度条映射变量m_progress这就需要在传输一段文件后就更新m_progress的值使进度条前进 也 ...

  9. openlayers之地图截图

    方法1 //this.map._this为初始化地图对象 this.map._this.once('postcompose', function (event) { var canvas = even ...

  10. vue路由(基于VScode开发)

    index.js如果在router目录下,代表这个js文件只是路由使用 main.js中为全局,需要引入使用到的组件,一般vue中不用写东西vue中el挂载哪个就哪个组件为根目录,传值数据绑定的时候在 ...