【BZOJ4259】 残缺的字符串

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计算即可。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cmath>
 4 #include <cstring>
 5
 6 #define R register
 7 #define maxn 1048576
 8 typedef long double db;
 9 const db pi = acosl(-1);
10 char A[maxn], B[maxn];
11 struct Complex {
12     db x, y;
13     inline Complex operator - (const Complex &that) const {return (Complex) {x - that.x, y - that.y};}
14     inline Complex operator * (const Complex &that) const {return (Complex) {x * that.x - y * that.y, x * that.y + y * that.x};}
15     inline void operator += (const Complex &that) {x += that.x; y += that.y;}
16 } w[maxn];
17 int N;
18 void init()
19 {
20     R int h = N >> 1;
21     for (R int i = 0; i < h; ++i) w[i + h] = (Complex) {cos(2 * pi / N * i), sin(2 * pi / N * i)};
22     for (R int i = h; i--; ) w[i] = w[i << 1];
23 }
24 void bit_reverse(R Complex *a, R Complex *b)
25 {
26     for (R int i = 0; i < N; ++i) b[i] = a[i];
27     for (R int i = 0, j = 0; i < N; ++i)
28     {
29         i > j ? std::swap(b[i], b[j]), 1 : 0;
30         for (R int l = N >> 1; (j ^= l) < l; l >>= 1);
31     }
32 }
33 void dft(R Complex *a)
34 {
35     for (R int l = 2, m = 1; m != N; l <<= 1, m <<= 1)
36         for (R int i = 0; i < N; i += l)
37             for (R int j = 0; j < m; ++j)
38             {
39                 R Complex tmp = a[i + j + m] * w[j + m];
40                 a[i + j + m] = a[i + j] - tmp;
41                 a[i + j] += tmp;
42             }
43 }
44 Complex a[maxn], b[maxn], ta[maxn], tb[maxn], tc[maxn], ans[maxn];
45 int aa[maxn], bb[maxn];
46 int main()
47 {
48     R int la, lb;
49     scanf("%s%s", A, B);
50     la = strlen(A); lb = strlen(B);
51     for (N = 1; N < (la + lb); N <<= 1);
52     init();
53     std::reverse(A, A + la);
54     for (R int i = 0; i < la; ++i) A[i] == ‘*‘ ? 0 : aa[i] = A[i] - ‘a‘ + 1;
55     for (R int i = 0; i < lb; ++i) B[i] == ‘*‘ ? 0 : bb[i] = B[i] - ‘a‘ + 1;
56
57     for (R int i = 0; i < la; ++i) a[i].x = aa[i] * aa[i] * aa[i], a[i].y = 0;
58     for (R int i = 0; i < lb; ++i) b[i].x = bb[i], b[i].y = 0;
59     bit_reverse(a, ta); bit_reverse(b, tb);
60     dft(ta); dft(tb);
61     for (R int i = 0; i < N; ++i) ans[i] += (ta[i] * tb[i]);
62
63     for (R int i = 0; i < la; ++i) a[i].x = -2 * aa[i] * aa[i], a[i].y = 0;
64     for (R int i = 0; i < lb; ++i) b[i].x = bb[i] * bb[i], b[i].y = 0;
65     bit_reverse(a, ta); bit_reverse(b, tb);
66     dft(ta); dft(tb);
67     for (R int i = 0; i < N; ++i) ans[i] += (ta[i] * tb[i]);
68
69     for (R int i = 0; i < la; ++i) a[i].x = aa[i], a[i].y = 0;
70     for (R int i = 0; i < lb; ++i) b[i].x = bb[i] * bb[i] * bb[i], b[i].y = 0;
71     bit_reverse(a, ta); bit_reverse(b, tb);
72     dft(ta); dft(tb);
73     for (R int i = 0; i < N; ++i) ans[i] += (ta[i] * tb[i]);
74
75     std::reverse(ans + 1, ans + N);
76     bit_reverse(ans, tc);
77     dft(tc);
78 //    for (R int i = 0; i < N; ++i) printf("%lf %lf\n", tc[i].x, tc[i].y);
79     for (R int i = la - 1; i < lb; ++i) if (fabs(tc[i].x / N) < 0.5) printf("%d ", i - la + 2);
80     return 0;
81 }
82 /*
83 399906 399924 399942 399960 399978 399996
84 */

FFT

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

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <bitset>
  4 #include <algorithm>
  5
  6 #define R register
  7 #define maxn 500010
  8 #define maxs 15635
  9 //#define inline
 10 char A[maxn], B[maxn];
 11 /*inline bool eq(R char a, R char b)
 12 {
 13     return a == b || a == ‘*‘ || b == ‘*‘;
 14 }*/
 15 typedef unsigned uint;
 16 int len;
 17
 18 #define set(v, x) (v[x >> 5] |= 1u << (x & 31))
 19 #define query(v, x) ((1u << (x & 31)) & v[x >> 5])
 20 uint p[26][32][maxs];
 21 uint aph[26][maxs], ans[maxs];
 22 inline void init(R int c)
 23 {
 24     R uint *t = p[c][0], *tt;
 25     for (R int i = 0; i <= len; ++i) t[i] = aph[c][i];
 26     for (R int i = 1; i < 32; ++i)
 27     {
 28         t = p[c][i]; tt = p[c][i - 1];
 29         for (R int j = 0; j <= len; ++j)
 30             t[j] = ((tt[j] >> 1) | ((tt[j + 1] & 1u) << 31));
 31     }
 32 }
 33 int cnt;
 34 inline void bit_and(R int c, R int l)
 35 {
 36     R int fir = l >> 5; R uint *t = p[c][l & 31];
 37     R int i = fir, j = 0;
 38     for (; i + 36 < len; i += 36, j += 36)
 39     {
 40         ans[j] &= t[i];
 41         ans[j + 1] &= t[i + 1];
 42         ans[j + 2] &= t[i + 2];
 43         ans[j + 3] &= t[i + 3];
 44         ans[j + 4] &= t[i + 4];
 45         ans[j + 5] &= t[i + 5];
 46         ans[j + 6] &= t[i + 6];
 47         ans[j + 7] &= t[i + 7];
 48         ans[j + 8] &= t[i + 8];
 49         ans[j + 9] &= t[i + 9];
 50         ans[j + 10] &= t[i + 10];
 51         ans[j + 11] &= t[i + 11];
 52         ans[j + 12] &= t[i + 12];
 53         ans[j + 13] &= t[i + 13];
 54         ans[j + 14] &= t[i + 14];
 55         ans[j + 15] &= t[i + 15];
 56         ans[j + 16] &= t[i + 16];
 57         ans[j + 17] &= t[i + 17];
 58         ans[j + 18] &= t[i + 18];
 59         ans[j + 19] &= t[i + 19];
 60         ans[j + 20] &= t[i + 20];
 61         ans[j + 21] &= t[i + 21];
 62         ans[j + 22] &= t[i + 22];
 63         ans[j + 23] &= t[i + 23];
 64         ans[j + 24] &= t[i + 24];
 65         ans[j + 25] &= t[i + 25];
 66         ans[j + 26] &= t[i + 26];
 67         ans[j + 27] &= t[i + 27];
 68         ans[j + 28] &= t[i + 28];
 69         ans[j + 29] &= t[i + 29];
 70         ans[j + 30] &= t[i + 30];
 71         ans[j + 31] &= t[i + 31];
 72         ans[j + 32] &= t[i + 32];
 73         ans[j + 33] &= t[i + 33];
 74         ans[j + 34] &= t[i + 34];
 75         ans[j + 35] &= t[i + 35];
 76     }
 77     for (; i <= len; ++i, ++j) ans[j] &= t[i];
 78 }
 79
 80 //std::bitset<maxn> aph[26], ans;
 81 int fail[maxn];
 82 int r[maxn];
 83 inline bool cmp(R int a, R int b) {return A[a] < A[b] || (A[a] == A[b] && (a & 31) < (b & 31));}
 84 int main()
 85 {
 86 //    freopen("str.in", "r", stdin);
 87 //    freopen("str.out", "w", stdout);
 88     scanf("%s%s", A, B);
 89     R int la = strlen(A), lb = strlen(B);
 90     len = lb >> 5;
 91     R int xcnt = 0;
 92     for (R int i = 0; i < la; ++i) xcnt += A[i] == ‘*‘;
 93     for (R int i = 0; i < lb; ++i) xcnt += B[i] == ‘*‘;
 94     /*if (!xcnt)
 95     {
 96         fail[1] = 0;
 97         for (R int i = la; i; --i) A[i] = A[i - 1];
 98         for (R int i = lb; i; --i) B[i] = B[i - 1];
 99         for (R int i = 2, p = 0; i <= la; ++i)
100         {
101             while (p && A[p + 1] != A[i]) p = fail[p];
102             A[p + 1] == A[i] ? ++p : 0;
103             fail[i] = p;
104         }
105         for (R int i = 1, p = 0; i <= lb; ++i)
106         {
107             while (p && A[p + 1] != B[i]) p = fail[p];
108             A[p + 1] == B[i] ? ++p : 0;
109             if (p == la)
110             {
111                 printf("%d ", i - la + 1);
112                 p = fail[p];
113             }
114         }
115         puts("");
116         return 0;
117     }*/
118     for (R int i = 0; i < lb; ++i)
119     {
120         if (B[i] != ‘*‘) set(aph[B[i] - ‘a‘], i);
121         else for (R int j = 0; j < 26; ++j) set(aph[j], i);
122         set(ans, i);
123     }
124     for (R int i = 0; i < 26; ++i) init(i);
125 //    fprintf(stderr, "%d %d\n", ‘*‘, ‘a‘);
126     for (R int i = 0; i < la; ++i) r[i] = i;
127     std::sort(r, r + la, cmp);
128     for (R int i = 0; i < la; ++i)
129         if (A[r[i]] != ‘*‘)
130             bit_and(A[r[i]] - ‘a‘, r[i]);
131 //            ans &= (aph[A[i] - ‘a‘] >> i);
132     for (R int i = 0; i + la - 1 < lb; ++i) if (query(ans, i)) printf("%d ", i + 1); puts("");
133     return 0;
134 }

bitset

时间: 2024-11-05 14:38:14

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

BZOJ4259 : 残缺的字符串

假设字符串是从第0位开始的,那么对于两个长度都为n的字符串A,B,定义距离函数\[dis(A,B)=\sum_{i=0}^{n-1}(A[i]-B[i])^2[A[i]!='*'][B[i]!='*']\] 若把*号都设置为0,那么有\[dis(A,B)=\sum_{i=0}^{n-1}(A[i]-B[i])^2A[i]B[i]\] 如果$dis(A,B)=0$,那么A和B完全匹配. 对于这个问题,假设我们枚举B的末尾位置i,设$f[i]=dis(A,B[i-m+1,i])$,那么B的这一个子串

Luogu P4173 残缺的字符串

P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C(x,y) =A(x)- B(y)\),若为0,表示B串中以第\(y\)个字符结尾的字符可以与A串中以\(x\)节为结尾的字符可以匹配 \(P(x) = \sum_{i = 0}^{m - 1}C(i,x - m + i + 1)\) 但是很遗憾当\(P(x)\),等于零时,只能够说明上述子串的字符

P4173 残缺的字符串

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

@bzoj - [email&#160;protected] 残缺的字符串

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. 你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这

【BZOJ】4259: 残缺的字符串

[题意]给定长度为m的匹配串B和长度为n的模板串A,求B在A中出现多少次.字符串仅由小写字母和通配符" * "组成,其中通配符可以充当任意一个字符.n<=3*10^5. [算法]FFT [题解]假设模板串的数组A用0~26代表所有字符,0为通配符,匹配串的数组B同理,那么用表示差异的经典套路: $$C_n=\sum_{i=0}^{m-1}(A_{n+i}-B_i)^2*A_{n+i}*B_i$$ 那么可以看出$C_n=0$当且仅当$S_A[n,n+m-1]=S_B[0,m-1]$

P4173 残缺的字符串 fft

题意:给你两个字符串,问你第一个在第二个中出现过多少次,并输出位置,匹配时是模糊匹配*可和任意一个字符匹配 题解:fft加速字符串匹配; 假设上面的串是s,s长度为m,下面的串是p,p长度为n,先考虑没有*的情况那么\(\sum_{j=1}^m(s_{i+j}-p_j)^2=0\)就表示能够从i开始匹配,现在考虑有*的情况,我们只需要让有*的和任意字符匹配即可,那么把公式变成\(\sum_{j=1}^m(s_{i+j}-p_j)^2*s_{i+j}*p_j)=0\),但是fft正向匹配太慢了,我

[Luogu P4173]残缺的字符串 ( 数论 FFT)

题面 传送门:洛咕 Solution 这题我写得脑壳疼,我好菜啊 好吧,我们来说正题. 这题.....emmmmmmm 显然KMP类的字符串神仙算法在这里没法用了. 那咋搞啊(或者说这题和数学有半毛钱关系啊) 我们考虑把两个字符相同强行变为一个数学关系,怎么搞呢? 考虑这题是带通配符的,我们可以这样设: \(C(x,y)=(A[x]-B[y])^2*A[x]*B[y]\) 因此,我们可以看出两个字符一样当且仅当\(C(x,y)=0\) 因此,我们再设一个函数\(P(x)\)表示\(B\)串以第\

4259. 残缺的字符串

传送门 用 $FFT$ 搞字符串匹配,神仙操作.... 对于两个字符串 $A,B$,定义 $dis(A,B)=\sum_i(A_i-B_i)^2$ 显然当且仅当 $A=B$ 时,$dis(A,B)=0$ 这一题还有要求,'*' 为通配符,所以这题的 $dis(A,B)=\sum_i((A_i-B_i)^2[A_i!='*'][B_i!='*'])$ 发现这时如果设 '*' 为 $0$,则 $dis(A,B)=\sum_i((A_i-B_i)^2A_iB_i)$ 对于此题,设 $A$ 串为模板串,

luogu4173 残缺的字符串

对于一类带有通配符的字符串匹配问题,我们考虑构造匹配函数,通过匹配函数的值来判断匹配的位置. 先考虑一个不带通配符的问题:给定两个字符串\(A,B\),判断\(B\)的哪些位置能与\(A\)匹配. 除了kmp,我们同样可以考虑构造匹配函数来解决匹配问题,首先将\(A\)串翻转同时在其末尾补\(0\),构造函数\(f_i=\sum_{j=0}^i(A_i-B_{i-j})^2\),那么\(B\)中在第\(i\)个位置结尾的长度为\(|A|\)的子串能与\(A\)匹配当且仅当\(f_i=0\).将函