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. # ACM奇淫技巧

    目录 ACM奇淫技巧 差分操作 坐标旋转 ACM 卡常优化 vsc代码块(头文件模板) 读入输出优化 逗号表达式 内联函数inline 寄存器变量register 条件判断加减代替取模 自增运算符优化 ...

  2. 06: zabbix常见面试题

    1.1 zabbix架构 1.zabbix理论 1)Zabbix是一个企业级的.开源的.分布式的监控套件,Zabbix可以监控网络和服务的监控状况. 2)Zabbix利用灵活的告警机制,允许用户对事件 ...

  3. Android Studio 配置Gradle总结

    一, 问题:①换个新电脑安装完Android Sutdio第一次打开一个工程巨慢怎么办? ② 手动配置Gradle Home为什么总是无效? ③ 明明已经下载了Gradle,配置了gradle hom ...

  4. php过滤微信昵称中的表情

    function filterNickname($nickname) { $nickname = preg_replace('/[\x{1F600}-\x{1F64F}]/u', '', $nickn ...

  5. AGC009E Eternal Average

    atc 神题orz 那个擦掉\(k\)个数然后写上一个平均值可以看成是\(k\)叉Huffman树的构造过程,每次选\(k\)个点合成一个新点,然后权值设为平均值.这些0和1都会在叶子的位置,同时每个 ...

  6. 分布式的几件小事(四)dubbo负载均衡策略和集群容错策略

    1.dubbo负载均衡策略 ①random loadbalance 策略 默认情况下,dubbo是random loadbalance 随机调用实现负载均衡,可以对provider不同实例设置不同的权 ...

  7. kill指定用户所有进程

    在linux系统管理中,我们有时候需要kill某个用户的所有进程,这里有以下几种方法,以heboan用为例 pkill方式 pkill -u heboan killall方式 killall -u h ...

  8. postMessage解决iframe跨域问题

    转:https://juejin.im/post/5b8359f351882542ba1dcc31 https://juejin.im/post/590c3983ac502e006531df11 ht ...

  9. 深入简出mysql--第一部分

    第二章: 1.sql分类 DDL(Data Definition Languages)语句:数据定义语言,这些语句定义了不同的数据段.数据库.表.列.索引等数据库对象的定义. 常用的语句关键字主要包括 ...

  10. Fiddler实现iPhone手机抓包

    最近某小程序大火,许多非专业人员也在跃跃欲试,但是在查找自己的session_id的时候卡住了,本文只从技术方面介绍如何通过通过Fiddler来抓取手机的数据,不涉及如何作弊... 1.电脑上安装Fi ...