zoukankan      html  css  js  c++  java
  • 后缀数组专题

    很久没写过这东西了,复习一波。

    3238: [Ahoi2013]差异

    链接

    单调栈维护height数组,由于height是递增的,所以维护单调栈中维护每个height出现的次数。(还可以两遍单调栈求一个点是最小值的区间)

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<cmath>
     6 #include<cctype>
     7 #include<set>
     8 #include<queue>
     9 #include<vector>
    10 #include<map>
    11 using namespace std;
    12 typedef long long LL;
    13  
    14 inline int read() {
    15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    17 }
    18  
    19 const int N = 500005;
    20  
    21 char s[N];
    22 int t1[N], t2[N], c[N], sa[N], rnk[N], height[N], m = 130, n;
    23 LL sk[N], cnt[N];
    24  
    25 void getsa() {
    26     int *x = t1, *y = t2, i, p;
    27     for (i = 1; i <= m; ++i) c[i] = 0;
    28     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
    29     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    30     for (i = 1; i <= n; ++i) sa[c[x[i]]--] = i;
    31     for (int k = 1; k <= n; k <<= 1) {
    32         p = 0;
    33         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
    34         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
    35         for (i = 1; i <= m; ++i) c[i] = 0;
    36         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
    37         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    38         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
    39         swap(x, y);
    40         p = 2;
    41         x[sa[1]] = 1;
    42         for (i = 2; i <= n; ++i) 
    43             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
    44         if (p > n) break;
    45         m = p;
    46     }
    47 }
    48 void getheight() {
    49     for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
    50     int k = 0;
    51     height[1] = 0;
    52     for (int i = 1; i <= n; ++i) {
    53         if (rnk[i] == 1) continue;
    54         if (k) k --;
    55         int j = sa[rnk[i] - 1];
    56         while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
    57         height[rnk[i]] = k;
    58     }
    59 }
    60 int main() {
    61     scanf("%s", s + 1);
    62     n = strlen(s + 1);
    63     getsa();
    64     getheight();
    65     LL ans = 0;
    66     for (int i = 1; i <= n; ++i) ans += 1ll * (n - 1) * i;
    67     int top = 0;LL now = 0;
    68     for (int i = 2; i <= n; ++i) {
    69         LL tmp = 1;
    70         while (top && sk[top] >= height[i]) {
    71             now -= 1ll * cnt[top] * sk[top]; tmp += cnt[top]; top --;
    72         }
    73         sk[++top] = height[i]; cnt[top] = tmp; now += 1ll * height[i] * tmp;
    74         ans -= now * 2;
    75     }
    76     cout << ans;
    77     return 0;
    78 }
    View Code

    CF 1090 J. Two Prefixes

    链接

    题意:从第一个串中选一个前缀,从第二个串中选一个前缀,问可以组成多少个不同的串。

    kmp+后缀数组。

    正难则反,用总的减去出现了多次的。枚举第二个串,那么考虑那些串是已经被计算过的,考虑这个前缀的bordor,如果第一个串可以存在1~n-bordor的字符,那么就是以前计算过的。

    后缀数组求lcp。

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<cmath>
      6 #include<cctype>
      7 #include<set>
      8 #include<queue>
      9 #include<vector>
     10 #include<map>
     11 using namespace std;
     12 typedef long long LL;
     13 
     14 inline int read() {
     15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
     16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
     17 }
     18 
     19 const int N = 200005;
     20 char s[N], a[N], b[N];
     21 int t1[N], t2[N], c[N], sa[N], height[N], Log[N], p[N], f[N][20], rnk[N], n, m = 130, la, lb;
     22 LL sum[N];
     23 
     24 void getsa() {
     25     int *x = t1, *y = t2, i, p;
     26     for (i = 1; i <= m; ++i) c[i] = 0;
     27     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
     28     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
     29     for (i = n; i >= 1; --i) sa[c[x[i]]--] = i;
     30     for (int k = 1; k <= n; k <<= 1) {
     31         p = 0;
     32         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
     33         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
     34         for (i = 1; i <= m; ++i) c[i] = 0;
     35         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
     36         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
     37         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
     38         swap(x, y);
     39         p = 2;
     40         x[sa[1]] = 1;
     41         for (i = 2; i <= n; ++i) 
     42             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
     43         if (p > n) break ;
     44         m = p;
     45     }
     46 }
     47 void getheight() {
     48     for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
     49     int k = 0;
     50     height[1] = 0;
     51     for (int i = 1; i <= n; ++i) {
     52         if (rnk[i] == 1) continue;
     53         if (k) k --;
     54         int j = sa[rnk[i] - 1];
     55         while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
     56         height[rnk[i]] = k;
     57     }
     58 }
     59 void rmq() {
     60     Log[0] = -1;
     61     for (int i = 1; i <= n; ++i) Log[i] = Log[i >> 1] + 1; 
     62     for (int i = 1; i <= n; ++i) f[i][0] = height[i];
     63     for (int j = 1; j <= Log[n]; ++j) 
     64         for (int i = 1; i + (1 << j) - 1 <= n; ++i) 
     65             f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
     66 }
     67 int LCP(int l,int r) {
     68     if (l > r) swap(l, r);
     69     l ++;
     70     int k = Log[r - l + 1];
     71     return min(f[l][k], f[r - (1 << k) + 1][k]);
     72 }
     73 int main() {
     74     scanf("%s%s", a + 1, b + 1);
     75     la = strlen(a + 1), lb = strlen(b + 1);
     76     n = la + lb;
     77     for (int i = 1; i <= la; ++i) s[i] = a[i];
     78     for (int i = 1; i <= lb; ++i) s[i + la] = b[i];
     79     getsa();
     80     getheight();
     81     rmq();
     82 
     83     for (int i = 2; i <= la; ++i) {
     84         int len = min(LCP(rnk[i], rnk[la + 1]), la - i + 1);
     85         sum[len] ++;
     86     }
     87     for (int i = la; i >= 1; --i) sum[i] += sum[i + 1];
     88     p[1] = 0;
     89     for (int i = 2; i <= lb; ++i) {
     90         int j = p[i - 1];
     91         while (j && b[j + 1] != b[i]) j = p[j];
     92         if (b[j + 1] == b[i]) j ++;
     93         p[i] = j;
     94     }
     95     LL ans = 1ll * la * lb;
     96     for (int i = 2; i <= lb; ++i) 
     97         if (p[i]) ans -= sum[i - p[i]];
     98     cout << ans;
     99     return 0;
    100 }
    View Code

    CF 802 I. Fake News (hard)

    链接

    题意:求每个串出现次数的平方。

    单调栈维护height数组。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<cmath>
     6 #include<cctype>
     7 #include<set>
     8 #include<queue>
     9 #include<vector>
    10 #include<map>
    11 #define mem(a) memset(a, 0, sizeof(a))
    12 using namespace std;
    13 typedef long long LL;
    14 
    15 inline int read() {
    16     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    17     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    18 }
    19 
    20 const int N = 100005;
    21 char s[N];
    22 int t1[N], t2[N], c[N], sa[N], rnk[N], h[N], sk[N], pos[N], n, m = 130;
    23 
    24 void getsa() {
    25     int *x = t1, *y = t2, i, p;
    26     for (i = 1; i <= m; ++i) c[i] = 0;
    27     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
    28     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    29     for (i = n; i >= 1; --i) sa[c[x[i]]--] = i;
    30     for (int k = 1; k <= n; k <<= 1) {
    31         p = 0;
    32         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
    33         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
    34         for (i = 1; i <= m; ++i) c[i] = 0;
    35         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
    36         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    37         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
    38         swap(x, y);
    39         x[sa[1]] = 1;
    40         p = 2;
    41         for (i = 2; i <= n; ++i) 
    42             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
    43         if (p > n) break;
    44         m = p;
    45     }
    46 }
    47 void getheight() {
    48     for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
    49     int k = 0;
    50     h[1] = 0;
    51     for (int i = 1; i <= n; ++i) {
    52         if (rnk[i] == 1) continue;
    53         if (k) k --;
    54         int j = sa[rnk[i] - 1];
    55         while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
    56         h[rnk[i]] = k;
    57     }
    58 }
    59 void solve() {
    60     scanf("%s", s + 1);
    61     n = strlen(s + 1), m = 130;
    62     getsa();
    63     getheight();
    64     int top = 0, now;
    65     LL ans = 0, t1, t2; 
    66     for (int i = 2; i <= n + 1; ++i) {
    67         now = i;
    68         while (top && h[i] < sk[top]) {
    69             t1 = i - pos[top] + 1;
    70             t2 = sk[top] - max(sk[top - 1], h[i]);
    71             ans += t1 * t1 * t2;
    72             now = pos[top --];
    73         }
    74         while (top && sk[top] == h[i]) now = pos[top --];
    75         sk[++top] = h[i], pos[top] = now;
    76     }
    77     for (int i = 1; i <= n; ++i) 
    78         ans += n - i + 1 - max(h[rnk[i]], h[rnk[i] + 1]);
    79     cout << ans << "
    ";
    80 }
    81 int main() {
    82     freopen("1.txt", "r", stdin);
    83     for (int T = read(); T--; ) solve();
    84     return 0;
    85 }
    View Code

    POJ 3581 Sequence

    链接

    题意:将一个字符串分成三段,每段翻转后得到一个新字符串,是这个新字符串字典序最小。

    首先将字符串反转,后缀排序,取出最小的作为第一段。剩下如果再次取后缀最小的是不可以的。因为可能取到的第一个是最小的,但是与第二个合起来后,总的字典序不是最小的。所以我们将剩下的复制一遍,然后后缀排序。这时只取前面那一部分。

    样例:

    6 10 1 2 2 3 4

    样例来自

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<cmath>
     6 #include<cctype>
     7 #include<set>
     8 #include<queue>
     9 #include<vector>
    10 #include<map>
    11 using namespace std;
    12 typedef long long LL;
    13 
    14 inline int read() {
    15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    17 }
    18 
    19 const int N = 200005;
    20 int s[N], t1[N], t2[N], c[N], sa[N], rnk[N], height[N], disc[N], n;
    21 
    22 void getsa() {
    23     int *x = t1, *y = t2, i, p, m = n + 10;
    24     for (i = 1; i <= m; ++i) c[i] = 0;
    25     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
    26     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    27     for (i = n; i >= 1; --i) sa[c[x[i]]--] = i;
    28     for (int k = 1; k <= n; k <<= 1) {
    29         p = 0;
    30         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
    31         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
    32         for (i = 1; i <= m; ++i) c[i] = 0;
    33         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
    34         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    35         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
    36         swap(x, y);
    37         x[sa[1]] = 1;
    38         p = 2;
    39         for (i = 2; i <= n; ++i) 
    40             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
    41         if (p > n) break;
    42         m = p;
    43     }
    44 }
    45 int main() { 
    46     n = read();
    47     for (int i = 1; i <= n; ++i) s[i] = read();
    48     reverse(s + 1, s + n + 1);
    49     
    50     for (int i = 1; i <= n; ++i) disc[i] = s[i];
    51     sort(disc + 1, disc + n + 1);
    52     int cnt = 1;
    53     for (int i = 2; i <= n; ++i) if (disc[i] != disc[cnt]) disc[++cnt] = disc[i];
    54     for (int i = 1; i <= n; ++i) s[i] = lower_bound(disc + 1, disc + cnt + 1, s[i]) - disc;
    55         
    56     getsa();
    57     
    58     int k = 0;
    59     for (int i = 1; k <= 2; ++i) k = sa[i];
    60     for (int i = k; i <= n; ++i) printf("%d
    ",disc[s[i]]);
    61         
    62     n = k - 1;
    63     for (int i = 1; i <= k - 1; ++i) s[i + n] = s[i];
    64     n <<= 1;
    65     getsa();
    66     
    67     for (int i = 1; k > n / 2 || k <= 1; ++i) k = sa[i];
    68     for (int i = k; i <= n / 2; ++i) printf("%d
    ",disc[s[i]]);
    69     for (int i = 1; i < k; ++i) printf("%d
    ",disc[s[i]]);
    70     
    71     return 0;
    72 }
    View Code

    URAL - 1297:Palindrome 

    链接(vjudge)

    题意:求最长回文子串,如果有多个长度相同的,输出最早出现的。

    分析:manacher或者后缀数组。

    枚举一个点i左右分界点,然后求出$s[:i]$和$s[i:]$的lcp,后缀数组+rmq求。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<cmath>
     6 #include<cctype>
     7 #include<set>
     8 #include<queue>
     9 #include<vector>
    10 #include<map>
    11 using namespace std;
    12 typedef long long LL;
    13 
    14 inline int read() {
    15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    17 }
    18 
    19 const int N = 200005;
    20 char s[N];
    21 int t1[N], t2[N], c[N], sa[N], height[N], Log[N], f[N][20], rnk[N], n, m = 130;
    22 
    23 void getsa() {
    24     int *x = t1, *y = t2, i, p;
    25     for (i = 1; i <= m; ++i) c[i] = 0;
    26     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
    27     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    28     for (i = n; i >= 1; --i) sa[c[x[i]]--] = i;
    29     for (int k = 1; k <= n; k <<= 1) {
    30         p = 0;
    31         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
    32         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
    33         for (i = 1; i <= m; ++i) c[i] = 0;
    34         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
    35         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    36         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
    37         swap(x, y);
    38         p = 2;
    39         x[sa[1]] = 1;
    40         for (i = 2; i <= n; ++i) 
    41             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
    42         if (p > n) break ;
    43         m = p;
    44     }
    45 }
    46 void getheight() {
    47     for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
    48     int k = 0;
    49     height[1] = 0;
    50     for (int i = 1; i <= n; ++i) {
    51         if (rnk[i] == 1) continue;
    52         if (k) k --;
    53         int j = sa[rnk[i] - 1];
    54         while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
    55         height[rnk[i]] = k;
    56     }
    57 }
    58 void rmq() {
    59     Log[0] = -1;
    60     for (int i = 1; i <= n; ++i) Log[i] = Log[i >> 1] + 1; 
    61     for (int i = 1; i <= n; ++i) f[i][0] = height[i];
    62     for (int j = 1; j <= Log[n]; ++j) 
    63         for (int i = 1; i + (1 << j) - 1 <= n; ++i) 
    64             f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    65 }
    66 int LCP(int l,int r) {
    67     if (l > r) swap(l, r);
    68     l ++;
    69     int k = Log[r - l + 1];
    70     return min(f[l][k], f[r - (1 << k) + 1][k]);
    71 }
    72 int main() {
    73     scanf("%s", s + 1);
    74     n = strlen(s + 1);
    75     for (int i = 1; i <= n; ++i) s[i + n] = s[n - i + 1];
    76     n <<= 1;
    77     getsa();
    78     getheight();
    79     rmq();
    80     int len = 1, pos = 1;
    81     for (int i = 2; i <= n; ++i) {
    82         int j = n - (i - 1) + 1, now = min(min(n / 2 - i + 1, i - 1), LCP(rnk[i], rnk[j]));
    83         if (now * 2 >= len) {
    84             if (now * 2 > len) len = now * 2, pos = i - now;
    85             else if (i - now < pos) pos = i - now;
    86         }
    87         j = n - (i - 1) + 1, now = min(min(n / 2 - (i + 1) + 1, i - 1), LCP(rnk[i + 1], rnk[j]));
    88         if (now * 2 + 1 >= len) {
    89             if (now * 2 + 1 > len) len = now * 2 + 1, pos = i - now;
    90             else if (i - now + 1 < pos) pos = i - now;
    91         }
    92     }
    93     s[pos + len] = '';
    94     puts(s + pos);
    95     return 0;
    96 } 
    View Code

    POJ 3415:Common Substrings

    链接

    题意:求两个串的求长度不小于 k 的公共子串数量。

    分析:单调栈维护height数组。 

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<cmath>
      6 #include<cctype>
      7 #include<set>
      8 #include<queue>
      9 #include<vector>
     10 #include<map>
     11 using namespace std;
     12 typedef long long LL;
     13  
     14 inline int read() {
     15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
     16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
     17 }
     18  
     19 const int N = 200005;
     20 char s[N], a[N], b[N];
     21 int t1[N], t2[N], c[N], sa[N], rnk[N], height[N], sk[N], cnt[N], n, k;
     22  
     23 void getsa() {
     24     int *x = t1, *y = t2, i, p, m = 130;
     25     for (i = 1; i <= m; ++i) c[i] = 0;
     26     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
     27     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
     28     for (i = 1; i <= n; ++i) sa[c[x[i]]--] = i;
     29     for (int k = 1; k <= n; k <<= 1) {
     30         p = 0;
     31         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
     32         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
     33         for (i = 1; i <= m; ++i) c[i] = 0;
     34         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
     35         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
     36         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
     37         swap(x, y);
     38         p = 2;
     39         x[sa[1]] = 1;
     40         for (i = 2; i <= n; ++i) 
     41             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
     42         if (p > n) break;
     43         m = p;
     44     }
     45 }
     46 void getheight() {
     47     for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
     48     int k = 0;
     49     height[1] = 0;
     50     for (int i = 1; i <= n; ++i) {
     51         if (rnk[i] == 1) continue;
     52         if (k) k --;
     53         int j = sa[rnk[i] - 1];
     54         while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
     55         height[rnk[i]] = k;
     56     }
     57 }
     58 void solve() {
     59     scanf("%s%s", a + 1, b + 1);
     60     int la = strlen(a + 1), lb = strlen(b + 1);
     61     n = la + lb + 1;
     62     for (int i = 1; i <= la; ++i) s[i] = a[i];
     63     s[la + 1] = '';
     64     for (int i = 1; i <= lb; ++i) s[i + la + 1] = b[i];
     65     getsa();
     66     getheight();
     67     
     68     height[n + 1] = 0; 
     69     int top = 0, nowcnt;
     70     LL ans = 0, now = 0;
     71     for (int i = 2; i <= n + 1; ++i) {
     72         nowcnt = 0;
     73         if (height[i] < k) { top = now = 0; continue; }
     74         if (sa[i - 1] <= la) nowcnt = 1, now += height[i] - k + 1;
     75         while (top && sk[top] >= height[i]) {
     76             now -= cnt[top] * (sk[top] - height[i]);
     77             nowcnt += cnt[top];
     78             top --;
     79         }
     80         sk[++top] = height[i], cnt[top] = nowcnt;
     81         if (sa[i] > la) ans += now;
     82     }
     83     
     84     top = nowcnt = now = 0;
     85     for (int i = 2; i <= n + 1; ++i) {
     86         nowcnt = 0;
     87         if (height[i] < k) { top = now = 0; continue; }
     88         if (sa[i - 1] > la + 1) nowcnt = 1, now += height[i] - k + 1;
     89         while (top && sk[top] >= height[i]) {
     90             now -= cnt[top] * (sk[top] - height[i]);
     91             nowcnt += cnt[top];
     92             top --;
     93         }
     94         sk[++top] = height[i], cnt[top] = nowcnt;
     95         if (sa[i] <= la) ans += now;
     96     }
     97     printf("%lld
    ", ans);
     98 }
     99 int main() { 
    100     while (~scanf("%d", &k) && k) solve();
    101     return 0;
    102 }
    View Code

    4199: [Noi2015]品酒大会

    链接

    分析:后缀数组+并查集。对于第一问,r相似的对数也是r-1相似的对数,对于第二问,r相似的最大值同样也是r-1相似的最大值。

    然后只对于一个height值只需要求每一段最长的区间就行了。按照height值从大的往小的依次加入,每次加入合并一个会合并至少两个串,然后求出两边的size,相乘是第一问的答案,两边的最大最小值乘起来是第二问的答案。为什么没有维护次大值次小值:考虑合并的时候,将两个区间合并成一个,如果最小值和次小值都在一边,那么这一边是height大的时候的一个区间,可以与它取max而来,否则在两边的情况就是两边的最小值。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<cmath>
     6 #include<cctype>
     7 #include<set>
     8 #include<queue>
     9 #include<vector>
    10 #include<map>
    11 using namespace std;
    12 typedef long long LL;
    13  
    14 inline int read() {
    15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    17 }
    18  
    19 const int N = 300005;
    20  
    21 char s[N];
    22 int t1[N], t2[N], c[N], sa[N], rnk[N], height[N], m = 130, n;
    23 int fa[N], siz[N], mx[N], mn[N], a[N];
    24 LL ans2[N], ans1[N];
    25 
    26 void getsa() {
    27     int *x = t1, *y = t2, i, p;
    28     for (i = 1; i <= m; ++i) c[i] = 0;
    29     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
    30     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    31     for (i = 1; i <= n; ++i) sa[c[x[i]]--] = i;
    32     for (int k = 1; k <= n; k <<= 1) {
    33         p = 0;
    34         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
    35         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
    36         for (i = 1; i <= m; ++i) c[i] = 0;
    37         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
    38         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    39         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
    40         swap(x, y);
    41         p = 2;
    42         x[sa[1]] = 1;
    43         for (i = 2; i <= n; ++i) 
    44             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
    45         if (p > n) break;
    46         m = p;
    47     }
    48 }
    49 void getheight() {
    50     for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
    51     int k = 0;
    52     height[1] = 0;
    53     for (int i = 1; i <= n; ++i) {
    54         if (rnk[i] == 1) continue;
    55         if (k) k --;
    56         int j = sa[rnk[i] - 1];
    57         while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
    58         height[rnk[i]] = k;
    59     }
    60 }
    61 bool cmp(int x,int y) { return height[x] > height[y]; }
    62 int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
    63 void Union(int x,int y) {
    64     x = find(x), y = find(y);
    65     if (x == y) return ;
    66     if (siz[x] > siz[y]) swap(x, y);
    67     fa[x] = y, siz[y] += siz[x];
    68     mx[y] = max(mx[y], mx[x]), mn[y] = min(mn[y], mn[x]);
    69 }
    70 int main() {
    71 //    freopen("1.txt", "r", stdin);
    72     n = read(); 
    73     scanf("%s", s + 1);
    74     getsa();
    75     getheight();
    76     for (int i = 1; i <= n; ++i) {
    77         int x = read();
    78         mn[rnk[i]] = mx[rnk[i]] = x;
    79         siz[rnk[i]] = 1; fa[rnk[i]] = rnk[i];
    80     }
    81     for (int i = 1; i < n; ++i) a[i] = i + 1;
    82     sort(a + 1, a + n, cmp);
    83     memset(ans2, -0x3f, sizeof(ans2));
    84     for (int i = 1; i < n; ++i) {
    85         int x = find(a[i] - 1), y = find(a[i]);
    86         ans1[height[a[i]]] += 1ll * siz[x] * siz[y];
    87         LL tmp = max(max(1ll * mx[x] * mx[y], 1ll * mx[x] * mn[y]), max(1ll * mn[x] * mx[y], 1ll * mn[x] * mn[y]));
    88         ans2[height[a[i]]] = max(ans2[height[a[i]]], tmp);
    89         Union(x, y);
    90     }
    91     for (int i = n - 1; i >= 0; --i) {
    92         ans1[i] += ans1[i + 1];
    93         ans2[i] = max(ans2[i], ans2[i + 1]);
    94     }
    95     for (int i = 0; i < n; ++i) 
    96         printf("%lld %lld
    ", ans1[i], ans1[i] == 0 ? 0 : ans2[i]);
    97     return 0;
    98 }
    View Code

    4340: BJOI2015 隐身术

    链接

    题意:给定两个串 A,B 。问 B 中有多少个非空子串和 A 的编辑距离不超过 K。 不同位置的内容相同的子串算作多个。两个串的“编辑距离”指的是把一个串变成另一个串需要的最小的操作次数,每次操作可以插入、删除或者替换一个字符。

    分析:考虑枚举B的一个后缀i,计算这个后缀中多少个前缀是满足的。由于k比较小,考虑能否直接搜索这些位置。(x,y,z)表示当前A串在x位置,B串在y位置,前面已经修改了z次,那么可以直接求出他们的lcp,然后直接跳到这个位置。此时有三种状态(x+1,y,z+1),(x,y+1,z+1),(x+1,y+1,z+1),如果A走完了或者B走完了或者z=k了,就返回。如果A走完了或者A末尾剩下的可以全部删掉,那么就是找到合法的位置了,合法的位置可能是一段区间(因为可能会剩下一些修改的次数,可以删除一些字符),对于这个区间可以差分。

    由于只会搜索k层,复杂度就是$n imes 3^k$,加上后缀数组的复杂度$nlogn$

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<cmath>
      6 #include<cctype>
      7 #include<set>
      8 #include<queue>
      9 #include<vector>
     10 #include<map>
     11 using namespace std;
     12 typedef long long LL;
     13 
     14 inline int read() {
     15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
     16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
     17 }
     18 
     19 const int N = 200005;
     20 char s[N], a[N], b[N];
     21 int t1[N], t2[N], c[N], sa[N], height[N], Log[N], f[N][20], rnk[N], n, m = 130, la, lb, k, now;
     22 int sum[N];
     23 
     24 void getsa() {
     25     int *x = t1, *y = t2, i, p;
     26     for (i = 1; i <= m; ++i) c[i] = 0;
     27     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
     28     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
     29     for (i = n; i >= 1; --i) sa[c[x[i]]--] = i;
     30     for (int k = 1; k <= n; k <<= 1) {
     31         p = 0;
     32         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
     33         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
     34         for (i = 1; i <= m; ++i) c[i] = 0;
     35         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
     36         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
     37         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
     38         swap(x, y);
     39         p = 2;
     40         x[sa[1]] = 1;
     41         for (i = 2; i <= n; ++i) 
     42             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
     43         if (p > n) break ;
     44         m = p;
     45     }
     46 }
     47 void getheight() {
     48     for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
     49     int k = 0;
     50     height[1] = 0;
     51     for (int i = 1; i <= n; ++i) {
     52         if (rnk[i] == 1) continue;
     53         if (k) k --;
     54         int j = sa[rnk[i] - 1];
     55         while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
     56         height[rnk[i]] = k;
     57     }
     58 }
     59 void rmq() {
     60     Log[0] = -1;
     61     for (int i = 1; i <= n; ++i) Log[i] = Log[i >> 1] + 1; 
     62     for (int i = 1; i <= n; ++i) f[i][0] = height[i];
     63     for (int j = 1; j <= Log[n]; ++j) 
     64         for (int i = 1; i + (1 << j) - 1 <= n; ++i) 
     65             f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
     66 }
     67 int LCP(int l,int r) {
     68     l = rnk[l], r = rnk[r + la + 1];
     69     if (l > r) swap(l, r);
     70     l ++;
     71     int k = Log[r - l + 1];
     72     return min(f[l][k], f[r - (1 << k) + 1][k]);
     73 }
     74 void col(int l,int r) {
     75     l = max(l, now);
     76     r = min(r, lb); // B串中,以now为左端点,右端点在[l,r]之间的串可行的。 
     77     sum[k - (la - (l - now + 1)) + 1] ++; // l-now+1为B串的长度,la-(l-now+1)为A中的剩余,即需要删除的元素 
     78     sum[k - (la - (r - now + 1)) + 2] --;  
     79 }
     80 void dfs(int x,int y,int z) {
     81     int t = LCP(x, y);
     82     x += t, y += t;
     83     if (x > la || y > lb) {
     84         int R = k - z - (la - x + 1); // 还剩余的修改次数
     85         if (R >= 0) col(y - R - 1, y + R - 1); // 这个区间都是可行的 
     86         return ;
     87     }
     88     if (z == k) return ;
     89     dfs(x + 1, y + 1, z + 1); // 替换 
     90     dfs(x + 1, y, z + 1); // 删除A中的字符 
     91     dfs(x, y + 1, z + 1); // 删除B中的字符 
     92 }
     93 int main() {
     94     k = read();
     95     scanf("%s%s", a + 1, b + 1);
     96     la = strlen(a + 1), lb = strlen(b + 1);
     97     n = la + lb + 1;
     98     for (int i = 1; i <= la; ++i) s[i] = a[i];
     99     s[la + 1] = '$';
    100     for (int i = 1; i <= lb; ++i) s[i + la + 1] = b[i];
    101     getsa();
    102     getheight();
    103     rmq();    
    104     int m = k + k + 1; LL ans = 0;
    105     for (now = 1; now <= lb; ++now) { // 计算B的这个后缀中多少前缀是可行的。 
    106         for (int i = 1; i <= m; ++i) sum[i] = 0;
    107         dfs(1, now, 0);
    108         for (int i = 1; i <= m; ++i) if (sum[i] += sum[i - 1]) ans ++;
    109     }
    110     cout << ans;
    111     return 0;
    112 }
    View Code

    3277: 串

     
     

     

  • 相关阅读:
    shell:echo -e "33字体颜色"
    Linux配置swap
    软工2017第三周作业——词频效能分析
    ffmpeg——关于视频压缩
    软件工程2017第一次作业——随笔汇总
    软件工程2017第一次作业——随笔二
    软件工程2017第一次作业——随笔一
    02-分支结构
    iOS中如何知道app版本已更新
    socket编程中客户端常用函数 以及简单实现
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10211803.html
Copyright © 2011-2022 走看看